Files
llm-wiki/raw/company-tech-blogs/multitenancy-stripe-citus-schema-per-tenant.md
T

119 lines
12 KiB
Markdown

---
title: Citus (Microsoft) — Schema vs Row-based Multi-tenancy on Postgres
source_type: company-tech-blog
url: https://www.citusdata.com/blog/2016/10/03/designing-your-saas-database-for-high-scalability/
archive_url:
status: raw
confidence: low
tags: [ca-multi-tenancy, postgres, citus, schema-per-tenant, shared-schema]
related_projects: [ca-skeleton-operational-contract]
related_branches: [feature-tenant-context-policy, feature-repository-access-permission-contract]
created: 2026-05-22
last_reviewed: 2026-05-27
---
# Citus — Designing SaaS DB for High Scalability (Schema vs Row)
> Layer: `raw/company-tech-blogs/` — Citus Data (현 Microsoft) 2016 블로그. Postgres 환경에서 **schema-per-tenant** vs **shared schema + tenant_id** 의 실제 한계치를 가장 구체적 숫자로 다룬 사례.
> **출처 주의**: company-tech-blog 이므로 본 자료의 권장 사항을 "공식 best practice" 로 일반화 금지. ca-tmpl 의 shared schema 결정의 임계점 사례 reference 로만 사용.
> 검증된 요약은 `/ingest` 후 `wiki/concepts/`에 별도 작성.
## Parent / 활용 branch (필수)
| Branch | 이 자료가 정당화하는 결정 |
|---|---|
| [[raw/branch-notes/feature-tenant-context-policy]] | Topic 6 Multi-tenancy 대안 3 (schema-per-tenant) 의 사례 baseline. ca-tmpl 이 shared schema (Pool) 를 채택한 임계점 (~수백 tenant) 의 사례 근거. |
| [[raw/branch-notes/feature-repository-access-permission-contract]] | shared schema 채택 결정의 trade-off — application bug 한 줄 cross-tenant leak 위험을 CROSS_TENANT_ADMIN capability 의 명시적 enforcement 로 완화하는 정당화. |
| [[raw/project-notes/ca-skeleton-operational-contract]] | §18 Control Plane Contract (Tenant Context Policy) 의 Postgres 사례 reference. |
## 컨텍스트 / 왜 저장했는지
Postgres 환경에서 **schema-per-tenant** vs **shared schema + tenant_id** 의 실제 한계치를 가장 구체적인 숫자로 다룬 자료. ca-tmpl 이 shared schema 를 택한 결정의 임계점을 가늠하는 근거.
## 출처 / Source
- 원본 URL: https://www.citusdata.com/blog/2016/10/03/designing-your-saas-database-for-high-scalability/
- 관련: "At what scale does Postgres multi-tenancy need to shard?"
- 아카이브 URL: (미수집)
- 저자 / 조직: Citus Data (현 Microsoft Azure Database for PostgreSQL — Hyperscale)
- 발행일: 2016-10-03
- 마지막 확인일: 2026-05-27
- **재검증 결과 (2026-05-27) — CRITICAL FINDING**: 원본 URL WebFetch 성공 — 페이지는 접근 가능 (Ozgun Erdogan 작성, "Designing your SaaS Database for High Scalability"). 그러나 2026-05-25 capture 의 4개 quote (수백~수천 tenant cut-off, pg_class/pg_attribute overhead, Flyway 마이그레이션, search_path/plan cache invalidation) 는 **현재 페이지에서 NOT FOUND** — 페이지는 3 옵션 (one DB per tenant / one schema per tenant / shared tables) 과 shared-tables + tenant_id sharding 권장 (Google F1 기반), Alter Table 처리, JSONB/hstore semi-structured types 만 다루며 인용된 구체적 수치/도구/Postgres internals 는 본 URL 본문에 없음. 2026-05-25 capture 의 4개 quote 는 본 자료 출처가 **아닐 가능성** (다른 Citus 블로그 또는 paraphrase 가능성). claim strength `company-case-study` + `needs-confirmation` 유지하되, 본 raw 자료를 근거로 한 downstream claim 은 **출처 재추적 필수**.
## 핵심 인용 / Key quotes (verbatim, 2026-05-22 작성 시 인용)
> needs-confirmation [§Schema-per-tenant scaling — 2026-05-25 capture, 2026-05-27 페이지 NOT FOUND (본 quote 가 원본 URL 에 부재)] "Schema-per-tenant works well up to a few hundred to a few thousand tenants. Beyond that, Postgres metadata overhead (pg_class, pg_attribute) grows substantially."
> needs-confirmation [§Shared schema + tenant_id — 2026-05-25 capture, 2026-05-27 페이지 NOT FOUND (본 quote 가 원본 URL 에 부재)] "Shared schema with a tenant_id column scales to many more tenants but requires careful indexing — every index should include tenant_id as the leading column where queries filter by tenant."
> needs-confirmation [§Migrations — 2026-05-25 capture, 2026-05-27 페이지 NOT FOUND (본 quote 가 원본 URL 에 부재)] "Migrations on schema-per-tenant must be applied N times; tools like Flyway support this but rollout time grows linearly with tenant count."
> needs-confirmation [§Connection pooling — 2026-05-25 capture, 2026-05-27 페이지 NOT FOUND (본 quote 가 원본 URL 에 부재)] "Connection pooling is a primary pain point for schema-per-tenant: switching `search_path` per request invalidates plan cache and causes connection thrash."
> **[2026-05-27 verified] 원본 URL 에서 verbatim 확인된 별도 내용 (위 4개 quote 와 별개)**:
> - 페이지가 다루는 3 옵션: "Create one database per tenant," "Create one schema per tenant," "Have all tenants share the same table(s)."
> - 권장: shared tables + tenant_id sharding (Google F1 기반 hierarchical model).
> - 스케일: 별도 DB per tenant 는 5-50 tenant 까지만 적합, 수천 단위는 shared tables.
> - Schema 변경: "the database will either ensure that an Alter Table goes through across all shards, or it will roll it back."
> - Variable tenant data: JSONB/hstore/JSON semi-structured types 사용 권장.
## Claims Extracted / 추출된 주장
| Claim ID | Claim (이 자료가 직접 말하는 것) | Evidence quote | Strength | Applies to | Does not prove |
|---|---|---|---|---|---|
| CITUS-MT-C1 | Schema-per-tenant 는 수백~수천 tenant 까지 잘 동작, 그 이상에서는 Postgres metadata (pg_class, pg_attribute) overhead 가 substantial 하게 증가 | needs-confirmation [§Schema-per-tenant scaling] "Schema-per-tenant works well up to a few hundred to a few thousand tenants. Beyond that, Postgres metadata overhead (pg_class, pg_attribute) grows substantially." | `company-case-study` + `needs-confirmation` | Citus / Postgres 컨텍스트 (2016 시점) | 정확한 "수백" "수천" 의 cut-off 수치는 Postgres 버전 / 하드웨어 / 테이블 수에 따라 다름 — 본 인용은 order of magnitude 만 |
| CITUS-MT-C2 | Shared schema + tenant_id 는 더 많은 tenant 로 확장 가능하나 indexing 주의 필요 — query 가 tenant 로 filter 하는 모든 index 는 tenant_id 가 leading column 이어야 함 | needs-confirmation [§Shared schema + tenant_id] "Shared schema with a tenant_id column scales to many more tenants but requires careful indexing — every index should include tenant_id as the leading column where queries filter by tenant." | `company-case-study` + `needs-confirmation` | Postgres + shared schema multi-tenancy | tenant_id 가 leading column 이 아니면 무조건 성능 저하라는 일반화는 아님 — query plan 에 따라 다름 |
| CITUS-MT-C3 | Schema-per-tenant migration 은 N 번 적용되어야 함; Flyway 같은 도구가 지원하나 rollout 시간이 tenant 수에 비례 | needs-confirmation [§Migrations] "Migrations on schema-per-tenant must be applied N times; tools like Flyway support this but rollout time grows linearly with tenant count." | `company-case-study` + `needs-confirmation` | schema-per-tenant 운영 | rollout 의 parallelism / dry-run 권장은 본 인용에 없음 |
| CITUS-MT-C4 | Schema-per-tenant 의 1차 pain point 는 connection pooling — request 마다 `search_path` 변경이 plan cache invalidation + connection thrash 유발 | needs-confirmation [§Connection pooling] "Connection pooling is a primary pain point for schema-per-tenant: switching `search_path` per request invalidates plan cache and causes connection thrash." | `company-case-study` + `needs-confirmation` | schema-per-tenant + Postgres + connection pooler 사용 | PgBouncer 의 transaction-level pooling 으로 완화 가능한지는 본 인용에 없음 |
## Usage Boundaries / 적용 경계
- **이 자료가 직접 증명하는 것**:
- 2026-05-27 verbatim 재확인 완료: 3 옵션 분류 (one DB / one schema / shared tables), shared tables + tenant_id sharding 권장, 별도 DB 는 5-50 tenant 까지만, Alter Table all-or-rollback 보장, JSONB/hstore 권장
- `CITUS-MT-C1` ~ `C4`: **본 quote 들이 원본 URL 에 부재** — 출처 재추적 필요 (다른 Citus 블로그 또는 paraphrase 가능성)
- **이 자료가 증명하지 않는 것**:
- 본 자료가 공식 Postgres 가이드라는 보증 (Citus 는 Postgres extension vendor 였고 2019년 Microsoft 인수, 본 블로그는 vendor case study)
- 2026 시점의 Postgres 14+ 또는 PgBouncer 신버전에서 동일 한계가 그대로 유지되는지 (페이지 outdated 가능성)
- 모든 SaaS 가 수천 tenant 에서 schema-per-tenant 를 포기해야 한다는 일반화 (use case 별 trade-off)
- **내 프로젝트에 적용하려면 추가 확인이 필요한 것**:
- ca-tmpl 의 예상 tenant 수가 수십 / 수백 / 수천 중 어디인지 (임계 판단의 입력값)
- shared schema 채택 시 모든 index 에 tenant_id 를 leading column 으로 포함하는 규약을 ca-tmpl 의 schema migration policy 에 명문화했는지
- 본 raw 인용 verbatim 의 정확성은 페이지 사람 검증 또는 archive.org snapshot 으로 보강
- "company-tech-blog" 이므로 wiki 추출 시 AWS / Hibernate 공식 자료와 corroboration 필요 (공식 best practice 로 단정 금지)
## 메모 / Notes (내 프로젝트 해석)
> 본 섹션은 자료 직접 인용 아님. ca-tmpl 결정 컨텍스트 해석.
- isolation 수준 (shared/schema-per-tenant/db-per-tenant):
- **Schema-per-tenant**: 같은 DB, 다른 schema. Postgres `search_path` 또는 fully-qualified table name.
- **Shared schema + tenant_id**: ca-tmpl 모델.
- tenant resolution 방식: 둘 다 application layer가 결정. schema-per-tenant는 connection 단위로 `SET search_path`.
- scale 한계 (구체 수치):
- Schema-per-tenant: ~수천 tenant까지. catalog bloat, autovacuum 부하, plan cache miss.
- Shared schema: tenant 수는 제약 없음. 다만 단일 테이블 row 수가 수억 → partition 또는 Citus 같은 sharding 필요.
- 운영 복잡도:
- schema-per-tenant: tenant 추가/삭제 자동화 스크립트 필수. 백업/복원이 tenant별 가능 (장점).
- shared schema: 단일 마이그레이션. 단점은 tenant별 백업이 사실상 불가 (logical export로 우회).
- security/compliance:
- schema-per-tenant는 Postgres role/grant로 OS 레벨 분리 가능 → application bug 방어막
- shared schema는 application bug 한 줄로 cross-tenant leak
- 비용: 둘 다 단일 DB instance → 인프라 비용 동일. 운영 비용은 schema-per-tenant가 더 큼.
- ca-tmpl과의 차이:
- ca-tmpl은 shared schema 선택. tenant 수가 ~수십 단위면 schema-per-tenant도 충분히 운영 가능했지만, 마이그레이션/connection pool 복잡도를 회피하기 위해 shared 채택.
- **임계 지점**: tenant 수가 수백 단위 + 규제(GDPR/금융권) 요구 시 schema-per-tenant 또는 stamp(=db-per-tenant) 검토.
## Related / 관련
- 같은 주제 다른 raw:
- [[raw/official-docs/multitenancy-aws-saas-tenant-isolation-whitepaper]] — AWS 의 Silo/Pool/Bridge 분류
- [[raw/official-docs/multitenancy-hibernate-user-guide]] — Hibernate ORM 의 3 strategy
- [[raw/official-docs/multitenancy-microservices-io-pattern]] — microservices.io database-per-service
- [[raw/company-tech-blogs/multitenancy-atlassian-tenant-context]] — shard + tenant context 운영 사례
- 인용하는 branch:
- [[raw/branch-notes/feature-tenant-context-policy]]
- [[raw/branch-notes/feature-repository-access-permission-contract]]
- 인용하는 project:
- [[raw/project-notes/ca-skeleton-operational-contract]] (§18)
- 인용한 wiki 요약: (미작성)