如何同步 Cosmos Db 中的相关集合?

How do you synchronize related collections in Cosmos Db?

我的应用程序需要支持按发票 ID 和按客户查找发票。出于这个原因,我创建了两个集合,其中存储了(完全)相同的发票文档:

显然你应该在查询时使用分区键,因为有两个查询我需要两个集合。我想以后可能还会有更多。

更新主要针对 InvoicesById 集合,但随后我还需要将更改复制到 InvoicesByCustomer(以及其他)。

是否有任何最佳实践或明智的方法来保持集合同步?

我正在考虑更改 Feed 等等。我想避免编写此同步代码并避免由于集合之间缺少事务(等)而导致不一致的风险。或者我可能在这里遗漏了一些重要的东西。

虽然我建议在暴力解决问题之前退一步,但更改 Feed 可以解决问题。


请在此处找到描述拆分问题的详细文章:Azure Cosmos DB. Partitioning.

根据 Microsoft 对可维护数据增长的建议,您应该 select 具有最高基数的分区键(在您的情况下,我假设它将是 InvoiceId)。对于 main reason:

Spread request unit (RU) consumption and data storage evenly across all logical partitions. This ensures even RU consumption and storage distribution across your physical partitions.

您不需要使用 CustomerId 分区键创建单独的容器,因为它不会为您提供所需的,最重要的是,未来可维护的性能,并且可能会在发票过多时导致物理分区数据倾斜链接到同一客户。

为了获得最佳和可扩展的查询性能,您很可能需要 InvoiceId 作为分区键和索引策略 CustomerId(以及未来的其他人)。

当您查询的数据分布在多个物理分区 (PP) 之间时,消耗中会有轻微的 RU 开销(绝对不是 RU 的倍增,而是每个请求耦合额外的 RU),但比较起来可以忽略不计当数据开始增长超过 50、100、150GB 时出现的问题。


为什么 CustomerId 可能不是预期增长超过 50GB 的数据集的最佳分区键?

主要原因是 Cosmos DB 设计为水平扩展,每个 PP 的配置吞吐量限制为 [total provisioned per container (or DB)] / [number of PP]

一旦由于超过 50GB 大小而发生 PP 拆分,您现有 PP 以及两个新创建的 PP 的最大吞吐量将低于拆分前。

想象一下以下场景(将天数视为衡量行动之间时间的尺度):

  1. 您已经创建了包含 10k RU 和 CustomerId 分区键(将生成一个底层 PP1)的容器。 每个 PP 的最大吞吐量是 10k/1 = 10k RUs
  2. 逐渐将数据添加到容器中,您最终拥有 3 个大客户,其发票为 C1[10GB]、C2[20GB] 和 C3[10GB]
  3. 当另一个客户使用 C4[15GB] 数据加入系统时,Cosmos DB 必须将 PP1 数据拆分为两个新创建的 PP2 (30GB) 和 PP3 (25GB)。 每个 PP 的最大吞吐量是 10k/2 = 5k RUs
  4. 另外两个客户 C5[10GB] C6[15GB] 被添加到系统中,并且都以 PP2 结束,这导致了另一个分裂 -> PP4 (20GB) 和 PP5 (35GB)。 每个 PP 的最大吞吐量现在是 10k/3 = 3.333k RUs

IMPORTANT: As a result on [Day 2] C1 data was queried with up to 10k RUs but on [Day 4] with only max to 3.333k RUs which directly impacts execution time of your query

这是在当前版本的 Cosmos DB (12.03.21) 中设计分区键时要记住的主要事项。