1. SaaS 多租户基础概念
1.1 什么是 SaaS
SaaS(Software as a Service,软件即服务)是一种通过互联网交付软件应用的模式。用户无需在本地安装、维护或管理软件,而是通过浏览器或 API 按需访问云端的服务。服务提供商负责底层基础设施、中间件、应用运行时的全生命周期管理。
SaaS 的核心特征包括:
- 多租户架构:一套应用实例同时服务多个客户(租户),租户之间逻辑隔离。
- 按需付费:用户按使用量(用户数、存储、API 调用次数)订阅,无需一次性购买许可证。
- 零运维:升级、补丁、扩缩容由提供商自动完成。
- 弹性扩展:基于云原生基础设施,支持从单租户到百万级租户的水平扩展。
关键指标:成熟的 SaaS 平台通常要求租户隔离延迟 < 5ms、租户元数据查询 QPS > 10,000、单租户数据恢复 RTO < 15 分钟。
1.2 多租户的定义
多租户(Multi-Tenancy)是指同一套软件实例能够同时服务多个相互隔离的租户。每个租户拥有独立的逻辑视图,包括用户身份、权限、配置、业务数据,但共享底层计算、存储和网络资源。
多租户与单租户的核心区别:
| 维度 | 单租户 | 多租户 |
|---|---|---|
| 实例数量 | 每个客户独立部署一套实例 | 所有客户共享一套实例 |
| 资源利用率 | 低(存在资源碎片) | 高(通过池化提升利用率) |
| 运维成本 | 线性增长(N 个客户 = N 倍运维) | 亚线性增长(新增租户几乎零成本) |
| 隔离强度 | 物理/虚拟化隔离 | 逻辑隔离为主,可叠加物理隔离 |
| 升级影响面 | 逐个升级,影响单个客户 | 一次升级影响所有租户(需灰度) |
1.3 租户隔离模型
租户隔离模型决定了数据如何在存储层进行分离。主流模型有三种:Database-per-Tenant、Schema-per-Tenant、Shared Table。选择哪种模型直接影响鉴权拦截链路的实现复杂度、数据恢复策略和自动化部署流水线。
1.3.1 Database-per-Tenant(独立数据库)
每个租户拥有独立的物理数据库实例或逻辑数据库。隔离级别最高,数据完全独立,备份恢复互不影响。适用于金融、医疗等强合规场景。
- 优点:最强数据隔离;支持按租户独立扩缩容;故障域最小。
- 缺点:资源开销大;连接池管理复杂;跨租户查询困难。
- 鉴权拦截特点:在连接层通过租户 ID 路由到对应数据库,鉴权拦截主要在网关层完成。
1.3.2 Schema-per-Tenant(独立 Schema)
所有租户共享同一个数据库实例,但每个租户拥有独立的 Schema(命名空间)。表结构相同,数据按 Schema 隔离。适用于中等规模 SaaS(几百到几千租户)。
- 优点:资源利用率高于独立数据库;支持 Schema 级备份;迁移成本较低。
- 缺点:共享数据库实例,存在资源争抢;跨 Schema 查询仍需应用层聚合。
- 鉴权拦截特点:在 ORM 层或数据访问层动态切换 Schema,鉴权拦截需同时验证租户身份和 Schema 映射。
1.3.3 Shared Table(共享表)
所有租户的数据存储在相同的表中,通过 tenant_id 列进行逻辑区分。隔离级别最低,但资源利用率最高。适用于超大规模、低合规要求的场景(如内部工具、日志分析)。
- 优点:存储成本最低;查询性能最优(单表扫描);运维最简单。
- 缺点:数据隔离完全依赖应用层;误操作可能导致租户数据泄露;备份恢复必须全量处理。
- 鉴权拦截特点:所有 SQL 查询必须强制附加
WHERE tenant_id = ?条件,鉴权拦截需在 SQL 解析层或 ORM 拦截器注入租户过滤。
常见陷阱:选择 Shared Table 模型时,如果鉴权拦截链路未在 SQL 层面强制注入 tenant_id 过滤,极易出现跨租户数据泄露。建议在自动化部署流水线中加入 SQL 静态扫描规则,检测是否存在缺失 tenant_id 的查询。
1.4 三种隔离模型对比
| 对比维度 | Database-per-Tenant | Schema-per-Tenant | Shared Table |
|---|---|---|---|
| 隔离强度 | 最高 | 中 | 低 |
| 资源开销 | 高(每个租户独立实例) | 中(共享实例,独立 Schema) | 低(共享实例和表) |
| 租户上限 | 几百 | 几千 | 百万级 |
| 备份恢复粒度 | 按租户独立备份 | 按 Schema 备份 | 全量备份 |
| 鉴权拦截复杂度 | 低(路由到独立 DB) | 中(动态 Schema 切换) | 高(SQL 级过滤注入) |
| 适用场景 | 金融、医疗、合规敏感 | 中型企业 SaaS | 超大规模、低成本场景 |
1.5 隔离模型选择对鉴权拦截链路的影响
鉴权拦截链路的核心职责是:在请求到达业务逻辑之前,完成租户身份识别、权限校验、数据路由规则注入。不同隔离模型决定了拦截链路的实现位置和复杂度:
- Database-per-Tenant:拦截链路主要在 API 网关层完成租户识别,然后路由到对应数据库连接池。数据层无需额外过滤。
- Schema-per-Tenant:拦截链路需要在网关层识别租户,并在 ORM 上下文(如 ThreadLocal)中设置当前 Schema。数据访问层自动切换。
- Shared Table:拦截链路必须在 SQL 执行前注入
tenant_id过滤条件。通常通过 MyBatis 拦截器、Hibernate 过滤器或数据库代理(如 ProxySQL)实现。
自动化部署建议:在 CI/CD 流水线中,建议为每种隔离模型配置独立的鉴权拦截测试套件。例如:Shared Table 模型必须包含 SQL 注入测试用例,验证所有 SELECT/UPDATE/DELETE 语句是否自动追加 tenant_id 条件。
1.6 隔离模型架构图
下图展示了三种隔离模型在 SaaS 多租户架构中的部署形态,以及鉴权拦截链路在每一层的作用位置:
1.7 隔离模型选择决策流程
在实际 SaaS 架构设计中,隔离模型的选择通常遵循以下决策树:
- 合规要求:如果租户数据必须物理隔离(如 GDPR、HIPAA),优先选择 Database-per-Tenant。
- 租户规模:预期租户数 < 500 且预算充足,选 Database-per-Tenant;500~5000 选 Schema-per-Tenant;> 5000 考虑 Shared Table 或混合模型。
- 运维能力:团队是否有能力管理大量数据库连接池和备份策略?如果否,优先 Schema-per-Tenant 或 Shared Table。
- 鉴权拦截复杂度:如果团队对 SQL 层拦截器不熟悉,避免选择 Shared Table,防止数据泄露。
- 混合模型:大型 SaaS 平台通常采用混合策略——高合规租户使用独立数据库,普通租户使用共享表,通过统一的鉴权拦截链路进行路由分发。
最佳实践:在自动化部署流水线中,建议将隔离模型作为部署配置参数(如
--isolation-model=shared-table),CI/CD 根据参数自动选择对应的鉴权拦截插件、数据库初始化脚本和测试套件。这样一套流水线即可支持所有隔离模型。