Skip to content

P57 项目场景面试:多租户 SaaS 系统怎么设计 ​

面试题:多租户(SaaS)系统怎么设计?多个客户共用一套系统,数据怎么隔离?

1. 三种数据隔离方案 ​

方案隔离强度成本适用
共享库共享表 + 租户字段弱(逻辑隔离)最低中小型 SaaS、免费/低端客户
共享库独立 Schema中中中型客户,隔离与成本均衡
独立数据库(每租户一库)强(物理隔离)最高大客户/金融/合规要求高

2. 推荐架构(共享库 + 租户字段为主) ​

text
所有业务表都加 tenant_id
每个请求从登录态/请求头解析出 tenant_id → 塞进上下文(ThreadLocal)
所有 SQL 强制带 tenant_id 条件

关键点:

① 租户上下文传递 ​

  • 登录后 Token/请求头携带租户标识;
  • 用 ThreadLocal 保存当前租户,切面在请求入口设置、finally 清理(防线程池串租户!);
  • 下游服务/RPC 也要透传租户 ID。

② 防止"串租户"(越权) ​

  • SQL 层强制:MyBatis 拦截器自动追加 AND tenant_id = ?;
  • 兜底:数据访问层统一校验租户;
  • 测试重点:A 租户不能查到 B 租户数据。

③ 共享资源按租户隔离 ​

  • 缓存 key 带租户:{tenantId}:{bizKey};
  • 文件/OSS 按租户目录分;
  • 定时任务、队列按租户隔离或标记;
  • 配置/套餐按租户维度。

3. 其他设计点 ​

  • 租户分级:大客户独立库/Schema,小客户共享,支持平滑升级迁移;
  • 数据删除/导出:合规要求租户数据可一键导出/删除;
  • 计费:按租户用量(API 调用、存储)计量;
  • 性能:tenant_id 加进索引(联合索引第一列或前缀),避免全表扫。

4. 加分点 ​

  • 提到"共享表方案要防止索引和查询被租户数据污染"(tenant_id 进索引);
  • 说清 ThreadLocal 在线程池中的坑:必须 remove,否则串租户;
  • 提到 MyBatis-Plus 有 TenantLineInnerInterceptor 可直接实现租户 SQL 改写。

一句话总结 ​

多租户 SaaS 常用"共享库 + tenant_id 逻辑隔离":请求入口解析租户塞 ThreadLocal、SQL 层强制加租户条件、缓存/文件按租户分,再按客户等级提供独立库方案;核心是防串租户和租户数据的强制隔离。

基于 VitePress 重建