2. 多租户模型设计
多租户(Multi-Tenancy)是 SaaS 架构的核心特征。租户隔离模式直接决定了数据安全性、运维复杂度、扩展成本和查询性能。业界主流方案可归纳为三种:数据库隔离、Schema 隔离、共享表隔离。本章从隔离性、性能、成本、开发复杂度四个维度进行系统对比,并给出选型决策树。
2.1 三种隔离模式的定义与结构
核心原则:隔离级别越高,安全性和性能隔离越好,但资源成本和运维开销也越高。选型本质是在“安全合规”与“运营效率”之间做权衡。
模式一:数据库隔离(Database per Tenant)
每个租户拥有独立的数据库实例。数据在物理层面完全隔离,一个租户的故障或慢查询不会影响其他租户。
- 适用场景:金融、医疗、政府等高合规行业;租户数量少(通常 < 200)但单租户数据量大。
- 优点:最强数据隔离;备份与恢复粒度细;可针对不同租户独立扩缩容。
- 缺点:连接数随租户线性增长;跨租户聚合查询困难;运维成本高。
模式二:Schema 隔离(Schema per Tenant)
所有租户共享同一个数据库实例,但每个租户拥有独立的 Schema(命名空间)。表结构相同,数据按 Schema 逻辑隔离。
- 适用场景:中型 SaaS 平台(租户数 200–5000);需要一定隔离性但希望控制数据库实例数量。
- 优点:隔离性较好;共享数据库连接池;跨租户查询可通过跨 Schema 实现。
- 缺点:单实例资源争用;Schema 数量过多时元数据管理复杂;迁移租户需 DDL 操作。
模式三:共享表隔离(Shared Table with Tenant ID)
所有租户共享同一套表结构,通过 tenant_id 列区分数据行。这是最经济的模式,也是实现最复杂的模式。
- 适用场景:超大规模 SaaS(租户数 > 5000);单租户数据量小;对隔离性要求较低。
- 优点:资源利用率最高;运维简单;跨租户分析查询方便。
- 缺点:数据隔离最弱;必须依赖应用层和 SQL 过滤保证安全;索引和查询复杂度高。
2.2 核心维度对比表
| 对比维度 | 数据库隔离 | Schema 隔离 | 共享表隔离 |
|---|---|---|---|
| 数据隔离级别 | 物理隔离(最高) | 逻辑隔离(中) | 行级隔离(低) |
| 单租户故障影响 | 不影响其他租户 | 可能影响同实例租户 | 可能影响全表 |
| 备份与恢复 | 按租户独立备份 | 按 Schema 备份 | 全表备份,恢复粒度粗 |
| 跨租户查询 | 困难(需跨库) | 较容易(跨 Schema) | 最方便(加 tenant_id 条件) |
| 数据库连接数 | 随租户线性增长 | 共享连接池 | 共享连接池 |
| 资源利用率 | 低 | 中 | 高 |
| 开发复杂度 | 低(天然隔离) | 中(需动态 Schema 路由) | 高(需强制 tenant_id 过滤) |
| 典型租户规模 | < 200 | 200 – 5000 | > 5000 |
2.3 隔离模式架构对比图
下图从数据容器维度展示三种模式的物理与逻辑边界:
2.4 选型决策树
实际项目中,选型通常不是“非此即彼”,而是根据租户特征分层组合。以下决策树可帮助快速定位:
2.5 混合模式实战案例
以某企业级 CRM SaaS 平台为例,其租户分层策略如下:
| 租户层级 | 隔离模式 | 租户数量 | 数据量/租户 | 路由标识 |
|---|---|---|---|---|
| 企业版 | 数据库隔离 | 50 | > 500 GB | shard_id → 数据库连接 |
| 专业版 | Schema 隔离 | 2000 | 50 – 500 GB | schema_name → 实例内路由 |
| 免费版 | 共享表隔离 | 30000 | < 5 GB | tenant_id → SQL 过滤 |
工程要点:混合模式下,应用层需要实现 多级租户路由。建议在 API 网关或 ORM 拦截器中统一注入租户上下文,根据租户等级动态选择数据源或 Schema。后续章节将详细讲解路由拦截链路的实现。
2.6 选型避坑清单
- 不要过早优化:初期租户数少时优先选择 Schema 隔离,后期再根据增长曲线迁移部分租户到独立库。
- 避免“全共享”陷阱:共享表隔离虽然成本低,但一旦出现 SQL 注入或
tenant_id过滤遗漏,将导致全平台数据泄露。 - 备份策略差异:数据库隔离模式下,备份脚本必须遍历所有数据库;共享表模式下需考虑增量备份对全表锁的影响。
- 连接池配置:数据库隔离模式需要为每个租户维护独立连接池,建议使用
HikariCP动态连接池组管理。 - 跨租户查询:如果业务需要频繁跨租户分析(如 BI 报表),共享表隔离是最优选择,但必须配合行级安全策略(RLS)。
安全红线:无论选择哪种隔离模式,永远不要在应用层信任 tenant_id。租户标识必须从认证 Token 中解析,禁止从请求参数或请求体中读取。这是多租户安全的第一原则。