在 Azure Cosmos DB for PostgreSQL 中为多租户 SaaS 应用建模
适用对象: Azure Cosmos DB for PostgreSQL(由 PostgreSQL 的 Citus 数据库扩展提供支持)
租户 ID 作为分片键
租户 ID 是工作负荷根目录处的列,或数据模型中层次结构的顶部。 例如,在此 SaaS 电子商务架构中,它是应用商店 ID:
此数据模型对于 Shopify 等业务来说是典型的。 它托管多个在线商店的网站,其中每个商店都与其自己的数据交互。
- 此数据模型包含一组表:商店、产品、订单、行项和国家/地区。
- 存储表位于层次结构的顶部。 产品、订单和行项都与商店相关联,因此在层次结构中较低。
- 国家/地区表与各个商店无关,它是跨商店的。
在此示例中,store_id
位于层次结构顶部,是租户的标识符。 这是正确的分片键。 选择 store_id
作为分片键可以跨单个工作器上的单个存储的所有表并置数据。
按商店分配表具有优势:
- 提供 SQL 覆盖,例如外键、JOIN。 单个租户的事务在存在每个租户的单个工作器节点上进行本地化。
- 实现单位数毫秒性能。 单个租户的查询将路由到单个节点,而不是并行化,这有助于优化网络跃点,并且仍可缩放计算/内存。
- 它会缩放。 随着租户数量的增长,可以添加节点并将租户重新平衡到新节点,甚至将大型租户隔离到自己的节点。 租户隔离允许提供专用资源。
多租户应用的最佳数据模型
在此示例中,我们应该按存储 ID 分发特定于存储的表,并创建 countries
引用表。
请注意,特定于租户的表具有租户 ID 并且是分布式的。 在我们的示例中,商店、产品和 line_items 是分布式的。 其余表是引用表。 在我们的示例中,国家/地区表是引用表。
-- Distribute large tables by the tenant ID
SELECT create_distributed_table('stores', 'store_id');
SELECT create_distributed_table('products', 'store_id', colocate_with => 'stores');
-- etc for the rest of the tenant tables...
-- Then, make "countries" a reference table, with a synchronized copy of the
-- table maintained on every worker node
SELECT create_reference_table('countries');
大型表都应具有租户 ID。
- 如果要将现有多租户应用迁移到 Azure Cosmos DB for PostgreSQL,则可能需要稍微非规范化,并将租户 ID 列添加到大型表中(如果缺少该列),然后回填该列的缺失值。
- 对于 Azure Cosmos DB for PostgreSQL 上的新应用,请确保租户 ID 存在于所有特定于租户的表中。
确保以复合键的形式将租户 ID 包含在分布式表的主要、唯一和外键约束上。 例如,如果表具有主键 id
,则将其转换为复合键 (tenant_id,id)
。
无需更改引用表的键。
有关最佳性能的查询注意事项
对租户 ID 进行筛选的分布式查询在多租户应用中运行效率最高。 确保查询始终限定为单个租户。
SELECT *
FROM orders
WHERE order_id = 123
AND store_id = 42; -- ← tenant ID filter
即使原始筛选器条件明确标识所需的行,也有必要添加租户 ID 筛选器。 租户 ID 筛选器虽然看似多余,但会告知 Azure Cosmos DB for PostgreSQL 如何将查询路由到单个工作器节点。
同样,在联接两个分布式表时,请确保这两个表的范围都限定为单个租户。 可以通过确保联接条件包括租户 ID 来完成范围限定。
SELECT sum(l.quantity)
FROM line_items l
INNER JOIN products p
ON l.product_id = p.product_id
AND l.store_id = p.store_id -- ← tenant ID in join
WHERE p.name='Awesome Wool Pants'
AND l.store_id='8c69aa0d-3f13-4440-86ca-443566c1fc75';
-- ↑ tenant ID filter
有多个常用应用程序框架的帮助程序库,便于在查询中包含租户 ID。 以下是说明:
后续步骤
现在,我们已探讨完可缩放应用的数据建模。 下一步是使用所选的编程语言连接和查询数据库。