1. 多租户架构基础:理解概念、隔离与模型选择

说到多租户,很多人第一反应就是“一个软件给好多家客户用”。嗯,对,也没错。但如果你只想到这层,那离真正设计好一个多租户系统还差得远。

我先讲个我自己的经历。几年前我带团队做一个SaaS平台,一开始图省事,所有客户的数据全塞在同一张表里,靠一个tenant_id字段区分。结果呢?上线不到三个月,某家客户的运营人员不小心写了个全表扫描的SQL,直接把其他客户的页面都拖垮了。那一周,我基本没睡过整觉。

所以说,多租户不光是“能共用”,更重要的是“能隔离”。而隔离到什么程度,怎么个隔法,就是本章要聊透的东西。

1.1 多租户核心概念

多租户(Multi-Tenancy)本质上是一种软件架构模式。一个运行实例,服务N个租户。每个租户感觉自己是独占的,但实际上底层资源是共享的。租户可以是企业、部门、项目组,甚至一个独立用户。

  • 租户(Tenant):逻辑上的客户单位。每个租户有自己的用户、配置、数据。
  • 租户标识:通常用 tenant_id 在请求链路中传递,贯穿所有服务。
  • 隔离边界:决定了租户之间能共享什么、不能共享什么。边界越强,安全性越高,成本也越高。

你想想看,租户之间最怕什么?怕数据串,怕性能抢,怕配置污染。所以设计的第一步,就是明确你要隔离到什么级别。

1.2 隔离级别:从“软”到“硬”

隔离级别我习惯分为三个层次。每个层次解决不同的问题,也带来不同的代价。

隔离级别 代表方案 数据安全 资源隔离 运维复杂度 成本
软隔离 共享数据库 + 行级标识 ★★ ★ ★ 最低
中隔离 共享数据库 + 独立Schema ★★★ ★★ ★★ 中等
硬隔离 独立数据库/独立实例 ★★★★★ ★★★★★ ★★★★ 最高

软隔离:所有租户的数据混在同一张表,靠 tenant_id 字段来区分。查询时WHERE tenant_id = ?。优点是省资源,一台数据库能塞几百个租户。缺点也明显——一个写错where条件,或者索引没命中,整个表被锁,所有租户一起遭殃。我前面提到的那个事故,就是软隔离的典型翻车案例。

中隔离:每个租户一个独立的Schema(可以说是数据库里的“文件夹”)。表结构相同,但数据物理上分开。查询时不需要 tenant_id 过滤,因为默认就在对应Schema里。隔离性比软隔离好不少,但数据库实例还是共享的,CPU和内存还是会互相影响。

硬隔离:每个租户一个独立的数据库实例,甚至是独立的虚拟机或容器。这是最彻底的方式,但也最烧钱。一般只有对安全合规要求极高的金融、医疗客户才会用。我记得有个做支付合规的项目,客户明确要求“你们的数据库不能跟我竞争对手的放在同一台服务器上”,那只能走硬隔离。

核心公式:
隔离强度 ∝ 安全性 × 成本 × 运维难度
没有最好的方案,只有最适合你业务场景的方案。

1.3 模型选择:三种主流方案

隔离级别决定了“隔到什么程度”,而模型选择决定了“用什么方式隔”。业界主流有三种模型,我把它们的差异整理成一张表。

模型 实现方式 典型场景 审计日志隔离难度 扩展性
共享表(Share Table) 所有租户共用一张表,tenant_id 行级隔离 中小型SaaS,租户数多且单个数据量小 高(依赖应用层过滤) 差(表太大后索引维护困难)
共享数据库·独立Schema(Share Database, Separate Schema) 每个租户一个Schema,表结构相同 中型SaaS,租户数几百到几千 中等(按库或Schema自然分隔) 中等(Schema数量有限制)
独立数据库(Separate Database) 每个租户一个独立数据库 大型客户/合规要求高的场景 低(天然物理隔离) 好(可水平拆分)

我的建议:对于《租户间审计日志隔离》这个课题,审计日志的隔离要求通常比业务数据更严格。如果一个租户能看到另一个租户的日志,那就是合规事故。所以哪怕业务数据用共享表,审计日志也建议至少做到中隔离(独立Schema)或硬隔离(独立数据库)。我见过太多客户因为审计日志漏隔离被罚钱的案例。

1.4 审计日志的特别之处

为什么审计日志对隔离的要求更高?因为审计日志本身就是为了“追溯”和“取证”而存在的。如果隔离没做好,日志就失去了可信度。想象一下,A租户的审计日志里混进了B租户的运维操作记录——到时候做内审,法律上完全站不住脚。

在实际项目中,我一般按以下原则决策:

  1. 可追溯:每一条日志必须能明确追溯到租户和操作人。
  2. 不可篡改:日志写入后,应用层不应该提供修改或删除接口。即使为了归档,也只能追加。
  3. 隔离原子性:如果选择软隔离,tenant_id 字段必须有强制索引,且所有查询都走索引。我曾经因为漏加一个索引,导致日志查询跨了租户,还好是内网测试阶段发现的……

避坑提醒:我曾经在项目中用了共享表做审计日志,然后做了个“超级管理员”角色可以查看所有租户的日志。结果产品手册没写清楚,普通租户的管理员以为也能看所有日志,投诉到法务。后来我们老老实实改成了独立Schema,才消停。所以,不要相信“代码里写好了过滤条件”这种话,物理隔离才是真的隔离。

1.5 用SVG清晰理清选择逻辑

下面这张图梳理了从“租户需求”到“模型选择”再到“审计日志隔离实现”的决策流程,帮你一次性看透全貌。

多租户架构决策流程 租户业务需求 选择隔离级别(软 / 中 / 硬) 共享表(软隔离) 独立Schema(中隔离) 独立数据库(硬隔离) 审计日志隔离实施 核心结论: 日志隔离必须是物理或逻辑上的强隔离, 绝不能仅依赖应用层的 tenant_id 过滤。

1.6 选型实战:一个简单公式

在实际决策时,我通常用下面这个简单的维度打分:

总得分 = 租户数权重 × 安全合规权重 × 运维能力权重

租户数权重:
  租户 < 50   → 3(倾向硬隔离)
  50-500      → 2(可中隔离)
  >500       → 1(倾向于软隔离或中隔离)

安全合规权重:
  金融/医疗/政府 → 3(必须硬隔离或中隔离+审计专用)
  一般企业      → 2
  内部工具      → 1

运维能力权重:
  专职DBA团队  → 3(可扛硬隔离运维)
  研发兼职运维  → 2
  无运维        → 1(尽量软隔离或SaaS托管)

把三个分数相乘,如果总分 ≥ 12,我建议至少上中隔离;如果 ≥ 18,那大概率得用硬隔离。当然,这只是启动时的判断,随着业务发展,你要做迁移预案。

记住:审计日志的隔离方案,最好在系统设计第一天就定下来。后面改隔离模型,比改业务数据隔离要痛苦得多——因为日志量巨大,而且可能有法律效力要求不能回退。你自己体会一下这个坑。