【系统架构设计】多租户架构:SaaS 系统的核心设计难题
内容提要
多租户架构的核心难题是隔离与资源公平。文章梳理了Silo、Bridge、Pool三种隔离模式,强调需在数据、连接、配额、计算四层同时加固。重点讨论了Pool模型下tenant_id漏过滤、吵闹邻居等风险,以及RLS安全网、连接池分区、限流等防御手段。同时介绍了Shopify Pod等混合分层方案,并指出跨租户分析应走数仓路径,与在线业务分离。
延伸解读
隔离谱系不是选择题,而是动态迁移路径
文章强调Silo、Bridge、Pool并非互斥选项,而是随租户生命周期动态调整的连续谱。实际工程中,大厂通常混用三档:长尾客户用Pool保证单位经济,大客户用Silo满足SLA与合规。关键不是选哪档,而是何时升级、是否可逆、路由能否无感切换。Shopify的Shop Mover和Citus的big tenant策略都展示了这种动态reposition的实践。
RLS是安全网,不是万能药
PostgreSQL的RLS能在执行计划层强制租户谓词,防止应用漏写WHERE tenant_id导致的泄露。但RLS无法防御存储层拖库、备份恢复错误、逻辑复制订阅方无策略等场景,也不能替代索引设计。它应作为深度防御的最后一道闸,而非合规叙事的全部。生产环境需配合FORCE RLS、SET LOCAL防连接池泄漏,并确保应用角色无BYPASSRLS权限。
吵闹邻居的防御需多层叠加
文章指出,吵闹邻居的防御不能单靠限流,需在连接、配额、计算、降级四层同时加固。具体包括:per-tenant限流与配额、连接池分区或只读副本分离、Kubernetes资源配额或V8 Isolate隔离,以及过载时按租户tier降级。关键是要有tenant维度的可观测性指标,否则事故发生后难以快速定位肇事租户。
跨租户分析必须与在线路径分离
Pool模型下,运营SQL看似方便,但在线路径扫全表会引发吵闹邻居和一致性风险。文章建议通过CDC将OLTP数据同步到数仓,在数仓层做跨租户聚合与分析,并强调在线请求必须保持单租户scope。Citus的reference table可用于共享只读维表,但跨租户事实表JOIN应限制在数仓或小结果集。
Q&A
多租户架构中,Silo、Bridge、Pool 三种模式分别是什么?
Silo 模式为每个租户提供独立的部署、进程或数据库,隔离最强但运维成本高;Bridge 模式共享应用但数据层独立(如独立数据库或 schema),隔离和成本居中;Pool 模式共享应用和数据库表,通过 tenant_id 区分租户,资源利用率高但存在吵闹邻居和数据泄露风险。
多租户架构中,吵闹邻居问题是什么?如何防御?
吵闹邻居指某个租户过度消耗共享资源(如 CPU、连接、IOPS),导致其他租户性能下降。防御手段包括:per-tenant 限流、配额管理、连接池分区、只读副本分离、计算隔离(如容器、V8 Isolate),以及过载时对非核心租户降级。
在 Pool 模型下,如何防止因漏写 tenant_id 导致的数据泄露?
可以采取多层措施:应用层强制使用 ORM 全局作用域或统一入口函数;代码审查和 CI 中静态分析 SQL,禁止无 tenant 条件的查询;数据库层启用 PostgreSQL 行级安全(RLS),并配合 SET LOCAL 设置当前租户,作为最后一道防线。
PostgreSQL 的 RLS 在多租户架构中如何配置?有什么注意事项?
配置步骤:对表启用 RLS 并 FORCE,创建策略使用 current_setting('app.current_tenant') 作为租户标识,应用在事务内 SET LOCAL 设置租户。注意事项:必须使用 SET LOCAL 防止连接池复用导致租户泄漏;超级用户或 BYPASSRLS 角色可绕过,生产应用角色不应具备;RLS 不能替代索引,且无法防御存储层泄露或备份恢复等场景。
多租户架构中,跨租户分析应该怎么做?
跨租户分析应避免在在线 OLTP 路径上执行,而应通过 CDC(如 Debezium)将数据变更同步到数据仓库(如 Snowflake、BigQuery),在数仓中进行聚合和分析。这样既不影响在线业务性能,也避免跨租户查询的复杂性和风险。
Shopify 的 Pod 架构是如何实现多租户隔离的?
Shopify 的 Pod 是一组隔离的数据存储集合(MySQL、Redis、memcached),多个商店共享一个 Pod,但每个请求只绑定一个 Pod,禁止跨 Pod 的在线 I/O。超大商户可以独占整个 Pod,通过 Sorting Hat 路由和 Shop Mover 实现动态迁移,从而在共享和隔离之间取得平衡。
多租户架构中,Schema-per-tenant 模式有什么优缺点?
优点:逻辑隔离更强,误连 schema 不会读到其他租户数据;支持 per-tenant 迁移和备份粒度。缺点:PostgreSQL 目录会膨胀,租户数多时 catalog 成为瓶颈;连接管理复杂,需要设置 search_path;迁移 fan-out 成本高。适用于租户数中等、需要逻辑分离的场景。
多租户架构中,如何选择隔离层级?
隔离层级分为 L1 逻辑(tenant_id)、L2 连接与配额、L3 进程/命名空间、L4 物理/网络。选择时需根据租户信任度、合规要求、成本等因素:一般 SaaS 至少需要 L1+L2;若租户上传代码,需 L3;金融、医疗等合规要求高的场景可能需要 L4。上层不能替代下层,应至少两层同时加固。