3、数据隔离策略:独立数据库模式、共享数据库独立Schema模式、共享数据库共享表模式、混合模式选型

数据隔离,说白了就是怎么把不同租户的数据「隔开」。

这个问题我当年刚做多租户系统时,踩过不少坑。有一次客户投诉说看到了别人的订单数据,吓得我连夜改方案。嗯,从那以后,我对数据隔离策略就特别敏感。

目前主流的方案有四种:独立数据库、共享数据库独立Schema、共享数据库共享表、以及混合模式。咱们一个一个聊。

3.1 独立数据库模式

每个租户一个独立的数据库实例。这是最「硬核」的隔离方式。

核心特点:

  • 物理隔离,数据安全性最高
  • 备份恢复互不影响
  • 可针对大租户单独做性能调优
  • 成本最高,管理最复杂

我在项目中遇到过一个大客户,月活用户上千万,数据量几十TB。这种场景下,独立数据库几乎是唯一选择。你想想看,如果跟其他小租户挤在一起,一个慢查询就能拖垮所有人。

适用场景:

  • 金融、医疗等强监管行业
  • 超大型租户(数据量 > 100GB)
  • 对SLA有严格要求的客户

3.2 共享数据库独立Schema模式

同一个数据库实例,但每个租户拥有独立的Schema(命名空间)。

我个人习惯把这个模式叫做「逻辑隔离」。所有租户共用数据库连接池,但表结构是分开的。

对比项 独立数据库 共享Schema
隔离级别 物理隔离 逻辑隔离
成本
扩展性 一般
管理复杂度

我曾经帮一个SaaS平台做过架构改造。他们一开始用共享表模式,结果租户之间数据互相污染。后来改成独立Schema,问题就解决了。其实对于大多数中小型租户,这个模式性价比最高。

注意:Schema数量过多时,数据库元数据管理会成为瓶颈。我建议单个实例不要超过500个Schema。

3.3 共享数据库共享表模式

所有租户共用同一套表,通过租户ID字段(tenant_id)来区分数据。

说白了,这就是最「省钱」的方案。但也是最容易出问题的方案。

-- 典型的共享表结构
CREATE TABLE orders (
    id BIGINT PRIMARY KEY,
    tenant_id VARCHAR(32) NOT NULL,
    order_no VARCHAR(64),
    amount DECIMAL(10,2),
    created_at DATETIME,
    -- 所有租户共用
    INDEX idx_tenant_id (tenant_id)
);

这里有个坑:所有查询都必须带上tenant_id条件。我见过一个团队忘了加这个条件,结果A租户的报表里出现了B租户的数据。嗯,那场面相当尴尬。

避坑指南:

  • ORM层强制注入tenant_id过滤条件
  • 数据库层面做行级安全策略(RLS)
  • 定期做数据完整性校验

3.4 混合模式

实际项目中,很少只用一种模式。我建议的做法是:按租户等级混合使用

举个例子,我之前设计的一个低代码平台:

  • 免费版租户:共享表模式,降低成本
  • 专业版租户:独立Schema模式,保证性能
  • 企业版租户:独立数据库模式,满足合规

你想想看,如果所有租户都用独立数据库,小租户根本付不起那个钱。反过来,如果大租户也用共享表,性能和安全都扛不住。

混合模式的核心原则:

  1. 根据租户付费等级决定隔离级别
  2. 支持租户升级时平滑迁移数据
  3. 统一的数据访问层,屏蔽底层差异

3.5 选型决策矩阵

我整理了一个决策表,方便你快速判断:

评估维度 独立数据库 独立Schema 共享表
数据安全性 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐
运维成本 ⭐⭐ ⭐⭐⭐ ⭐⭐⭐⭐⭐
扩展性 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐
适合租户规模

最后提醒一句:选型没有银弹。我见过太多团队一开始选共享表,后来数据量大了再迁移,那叫一个痛苦。建议一开始就预留好升级路径。

好了,数据隔离策略就聊到这儿。下一章咱们讲讲多租户下的缓存设计,那个坑更多,到时候我慢慢说。