multitenant

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Multitenant — Quick Reference

多租户架构——快速参考

Servir plusieurs clients (tenants) sur la même base de code avec isolation stricte et un coût d'infra contrôlé.
在同一代码库中为多个客户(租户)提供服务,同时保证严格隔离并控制基础设施成本。

Trois tiers d'isolation

三层隔离方案

TierIsolationCoûtCas d'usage
Tier 1 — Shared schemacolonne
tenant_id
partout, filtres SQL automatiques
FaibleStartups, free / petits clients
Tier 2 — Dedicated schemaun schéma PostgreSQL par tenantMoyenSMB, clients exigeants
Tier 3 — Dedicated DBune base entière par tenantÉlevéEnterprise, compliance stricte (HDS, FedRAMP)
Règle de migration : commencer Tier 1, migrer un client en Tier 2/3 quand il représente > 20 % du revenu OU exige un SLA spécifique.
层级隔离程度成本使用场景
Tier 1 — 共享Schema所有表均包含
tenant_id
字段,自动添加SQL过滤条件
初创公司、免费/小型客户
Tier 2 — 专属Schema每个租户对应一个PostgreSQL Schema中小企业、要求较高的客户
Tier 3 — 专属数据库每个租户对应一个完整数据库企业客户、严格合规要求(HDS、FedRAMP)
迁移规则:从Tier 1开始,当某一客户贡献超过20%的收入或需要特定SLA时,将其迁移至Tier 2/3。

Cinq invariants non-négociables

五项不可妥协的原则

  1. tenant_id
    propagé à chaque requête
    (AsyncLocalStorage / SecurityContext / middleware).
  2. PostgreSQL Row-Level Security (RLS) activé sur TOUTES les tables. Filet de sécurité contre un oubli applicatif.
  3. Tests d'isolation obligatoires. Tenant A ne doit jamais lire/écrire les données de B — y compris via tri, requête nuée, agrégat.
  4. Audit trail isolé par tenant. Pas de log multi-tenant cross-référencé sans permission explicite.
  5. Field-level encryption sur PII / secrets sensibles (Halite PHP, Eloquent Casts, libsodium).
  1. tenant_id
    需在每个请求中传递
    (通过AsyncLocalStorage / SecurityContext / 中间件)。
  2. 所有表必须启用PostgreSQL行级安全(RLS)。作为应用层遗漏时的安全兜底。
  3. 必须进行隔离测试。租户A绝不能读取/写入租户B的数据——包括通过排序、批量查询、聚合操作。
  4. 按租户隔离审计日志。未经明确许可,不得交叉引用多租户日志。
  5. 对PII/敏感机密数据进行字段级加密(可使用Halite PHP、Eloquent Casts、libsodium)。

Pattern minimal — Shared schema + RLS

最简实现方案——共享Schema + RLS

sql
ALTER TABLE invoices ADD COLUMN tenant_id UUID NOT NULL;
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON invoices
  USING (tenant_id = current_setting('app.tenant_id')::uuid);
php
// Symfony — middleware qui set la variable session pour RLS
$conn->executeStatement(
    'SET LOCAL app.tenant_id = :tid',
    ['tid' => $tenantId]
);
sql
ALTER TABLE invoices ADD COLUMN tenant_id UUID NOT NULL;
ALTER TABLE invoices ENABLE ROW LEVEL SECURITY;
CREATE POLICY tenant_isolation ON invoices
  USING (tenant_id = current_setting('app.tenant_id')::uuid);
php
// Symfony — 设置RLS会话变量的中间件
$conn->executeStatement(
    'SET LOCAL app.tenant_id = :tid',
    ['tid' => $tenantId]
);

Anti-patterns critiques

关键反模式

  • ❌ Oublier le filtre
    tenant_id
    dans une requête raw → fuite cross-tenant.
  • ❌ Cache Redis sans préfixe tenant → données de A retournées à B.
  • ❌ Job worker async qui perd le
    tenant_id
    → impossible de retrouver le contexte.
  • ❌ Signed URLs / tokens sans
    tenant_id
    dans le payload → utilisable cross-tenant.
  • ❌ Field encryption avec une clé unique partagée → compromission = exposition totale (préférer keys per tenant).
  • ❌ 在原生SQL查询中遗漏
    tenant_id
    过滤条件 → 跨租户数据泄露。
  • ❌ Redis缓存未添加租户前缀 → 租户A的数据返回给租户B。
  • ❌ 异步任务Worker丢失
    tenant_id
    → 无法恢复上下文。
  • ❌ 签名URL/令牌的载荷中未包含
    tenant_id
    → 可跨租户使用。
  • ❌ 使用单一共享密钥进行字段加密 → 密钥泄露导致全部数据暴露(建议按租户分配密钥)。

RBAC / ABAC

RBAC / ABAC权限控制

  • RBAC : rôles globaux (
    admin
    ,
    member
    ,
    viewer
    ) suffisent pour 80 % des cas.
  • ABAC : passer à des policies (Casbin, Cerbos, OPA) quand les règles dépendent d'attributs (région, montant, statut).
  • RBAC:全局角色(
    admin
    member
    viewer
    )可满足80%的场景需求。
  • ABAC:当规则依赖属性(地区、金额、状态)时,使用策略引擎(Casbin、Cerbos、OPA)。

Pour aller plus loin

拓展阅读

Patterns détaillés par tier, migration tier 1 → tier 2 sans downtime, tests d'isolation (Pest + tenant fixtures), RBAC/ABAC, exemples Laravel + Symfony, checklists par phase : voir
@.claude/skills/multitenant/REFERENCE.md
.
各层级的详细实现模式、Tier 1到Tier 2的无停机迁移方案、隔离测试(Pest + 租户测试数据)、RBAC/ABAC示例、Laravel + Symfony代码示例、各阶段检查清单:详见
@.claude/skills/multitenant/REFERENCE.md