SaaS 系统架构设计思路
SaaS 多租户难点:
1. 数据隔离(用户担心数据安全)
2. 定制化(和通用设计的冲突,客户要求加字段)
数据隔离
分为两种:
- 软隔离
数据在一起,带着租户 ID 查询
更好实现,更好维护 - 硬隔离
直接按租户分库
缺点:库会越来越多,可能成本高
软隔离可以通过架构来实现硬隔离。
- 数据库层封装:把所有的数据操作带着租户 ID。
是在底层驱动上封装,强制隔离租户。
具体做法:可以在驱动源码上修改;比较方便的做法应该是在驱动包上封一层(增强代理)。
(在 DAO 层用 AOP 也可以,但是可能被误删。所以不如在框架层面实现,避免写错。) - 消息队列封装:同理,在驱动包上强制检查租户 ID(没租户 ID 不让发消息),或者强制拼接上当前的租户 ID。
- Redis 封装:同理,拼装 key 的时候直接把租户 ID 拼接上。
租户 ID 怎么自动拼装
建议方案:上下文
例如使用 ThreadLocal
注意中间别开线程,如果中间有线程池的话,开新线程时需要把 ThreadLocal 复制过去(上下文传递)
这样就避免了调用链路上的每个方法都需要传租户 ID
设计联想:
ThreadLocal 这种解决方案就类似于 Session 共享用户信息
租户 ID 就类似于全链路日志系统的 TraceId(要求所有操作都有统一 ID)
定制化
- 业务数据 MySQL
- 动态扩展的可以用 NoSQL DB
大部分定制化数据和业务流程无关,一般是为了显示用的
(在 MySQL 里加 JSON 字段也可以,但是锁是个问题,自己解析 JSON 需要自己实现多版本并发控制;JSON 的查询也可能是个问题。总之不如用 MongoDB,都有现成解决方案。)
一个比较合理的思路
把大用户进行隔离:
一些集团性的用户(几千人)作为 VIP 用户单独进行分库;
小规模用户放在一起软分表。