2. 多租户模型:数据隔离模式、租户上下文传递与路由策略
多租户(Multi-Tenancy)是 SaaS 架构的核心。在 CI/CD 流水线中,鉴权与拦截链路必须准确识别当前请求属于哪个租户,并根据租户的隔离级别选择正确的数据源与资源路径。本章从数据隔离模式、上下文传递机制和路由策略三个维度展开,为后续的拦截与回滚设计奠定基础。
2.1 数据隔离模式:共享 vs. 独享
数据隔离决定了租户之间数据可见性与安全边界。主流模式有三种,下表从隔离粒度、运维成本和流水线适配三个角度进行对比:
| 隔离模式 | 数据库实例 | Schema / 表 | 隔离强度 | 运维成本 | CI/CD 适配要点 |
|---|---|---|---|---|---|
| 独享数据库 | 每个租户独立实例 | 独立 Schema | 最高 | 高(备份/扩容/迁移按租户) | 流水线需动态生成连接串;回滚按租户粒度执行 |
| 共享数据库·独享 Schema | 共享实例 | 每个租户独立 Schema | 中 | 中(Schema 管理复杂) | 流水线需在 SQL 迁移中注入 tenant_id 或 schema 前缀 |
| 共享数据库·共享表 | 共享实例 | 共享表 + tenant_id 列 | 最低 | 低(索引/分区需优化) | 流水线需确保所有 DML/DDL 包含租户过滤条件 |
实践建议:在 CI/CD 鉴权拦截链路中,建议将租户隔离模式作为元数据存储在配置中心。流水线在部署阶段根据租户元数据动态选择数据源,避免硬编码。
2.2 租户上下文传递
租户上下文(Tenant Context)是贯穿整个请求生命周期的租户标识与隔离属性集合。在微服务架构中,上下文传递必须做到无侵入、可追溯。
2.2.1 上下文数据结构
// TenantContext 核心字段
{
"tenantId": "t-abc123", // 租户唯一标识
"tenantCode": "acme-corp", // 租户业务编码
"isolationLevel": "SCHEMA", // 隔离模式: DATABASE | SCHEMA | TABLE
"region": "us-east-1", // 地域标识,用于多区域路由
"features": ["audit", "rbac"], // 租户特性标记
"requestId": "req-456def" // 请求链路追踪 ID
}
2.2.2 传递方式对比
| 传递方式 | 实现机制 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|---|
| HTTP Header | X-Tenant-Id / X-Tenant-Code | 简单、网关可解析 | 需手动透传,易丢失 | API 网关、边缘代理 |
| JWT Claims | Token 内嵌 tenant 字段 | 自包含、防篡改 | Token 体积增大 | OAuth2 / OpenID Connect |
| gRPC Metadata | gRPC 上下文附加键值对 | 框架原生支持 | 仅限 gRPC 协议 | 内部服务间调用 |
| ThreadLocal / AsyncLocal | 语言级上下文容器 | 代码侵入小 | 异步场景需显式传播 | 单体或服务内逻辑 |
避坑提醒:在 CI/CD 流水线中,如果使用 ThreadLocal 传递租户上下文,务必在异步任务(如消息队列、定时任务)中手动复制上下文,否则会导致租户信息丢失,引发数据泄露或鉴权失败。
2.3 租户路由策略
租户路由(Tenant Routing)决定请求到达后如何根据租户上下文选择数据源、服务实例或配置版本。在鉴权拦截链路中,路由发生在身份认证之后、业务逻辑之前。
2.3.1 路由层级
- DNS 路由: 根据租户子域名(tenant1.app.com)解析到不同集群或入口。
- API 网关路由: 根据 Header 或 Path 前缀(/api/tenant/{id}/)分发到后端服务。
- 数据访问层路由: 根据租户隔离模式选择数据库连接池或 Schema。
- 缓存路由: 为每个租户使用独立的 Redis 命名空间或 Key 前缀。
2.3.2 路由策略决策树
下图展示了在鉴权拦截链路中,系统如何根据租户元数据逐层决策路由目标:
2.4 流水线中的租户路由配置
在 CI/CD 流水线中,租户路由策略需要作为可配置的元数据注入到部署产物中。推荐使用配置中心(如 Consul、etcd、Nacos)存储以下路由表:
# 租户路由配置示例 (YAML)
tenants:
- id: "t-001"
code: "acme"
isolation: "SCHEMA"
datasource:
host: "db-shared-01.internal"
port: 5432
database: "saas_prod"
schema: "acme_schema"
cache:
prefix: "acme:"
region: "us-east-1"
- id: "t-002"
code: "globex"
isolation: "DATABASE"
datasource:
host: "db-globex.internal"
port: 5432
database: "globex_db"
schema: "public"
cache:
prefix: "globex:"
region: "eu-west-1"
流水线集成点:在部署阶段,流水线从配置中心拉取租户路由表,生成每个租户的数据库连接池、缓存命名空间和 API 路由规则。回滚时,只需将路由表指向上一版本的数据库快照或 Schema 备份,即可实现租户级快速回退。
2.5 本章小结
- 数据隔离模式决定了租户数据的物理边界,直接影响流水线中数据源的选择与回滚粒度。
- 租户上下文传递必须覆盖 HTTP、gRPC、异步消息等所有通信协议,避免上下文丢失导致的安全漏洞。
- 租户路由策略在鉴权拦截链路中起到承上启下的作用:认证后提取租户标识,业务前完成数据源与配置的绑定。
- 在 CI/CD 流水线中,将租户路由表作为一等配置资产管理,是实现自动化部署与精细化回滚的前提。