SaaS 多租户难点:
1. 数据隔离(用户担心数据安全)
2. 定制化(和通用设计的冲突,客户要求加字段)

数据隔离

分为两种:

  1. 软隔离
    数据在一起,带着租户 ID 查询
    更好实现,更好维护
  2. 硬隔离
    直接按租户分库
    缺点:库会越来越多,可能成本高

软隔离可以通过架构来实现硬隔离。

  • 数据库层封装:把所有的数据操作带着租户 ID。
    是在底层驱动上封装,强制隔离租户。
    具体做法:可以在驱动源码上修改;比较方便的做法应该是在驱动包上封一层(增强代理)。
    (在 DAO 层用 AOP 也可以,但是可能被误删。所以不如在框架层面实现,避免写错。)
  • 消息队列封装:同理,在驱动包上强制检查租户 ID(没租户 ID 不让发消息),或者强制拼接上当前的租户 ID。
  • Redis 封装:同理,拼装 key 的时候直接把租户 ID 拼接上。

租户 ID 怎么自动拼装

建议方案:上下文
例如使用 ThreadLocal
注意中间别开线程,如果中间有线程池的话,开新线程时需要把 ThreadLocal 复制过去(上下文传递)

这样就避免了调用链路上的每个方法都需要传租户 ID

设计联想:
ThreadLocal 这种解决方案就类似于 Session 共享用户信息
租户 ID 就类似于全链路日志系统的 TraceId(要求所有操作都有统一 ID)

定制化

  1. 业务数据 MySQL
  2. 动态扩展的可以用 NoSQL DB
    大部分定制化数据和业务流程无关,一般是为了显示用的

(在 MySQL 里加 JSON 字段也可以,但是锁是个问题,自己解析 JSON 需要自己实现多版本并发控制;JSON 的查询也可能是个问题。总之不如用 MongoDB,都有现成解决方案。)

一个比较合理的思路

把大用户进行隔离:
一些集团性的用户(几千人)作为 VIP 用户单独进行分库;
小规模用户放在一起软分表。