【发布时间】:2019-05-16 11:06:00
【问题描述】:
我们正在 .NET 中构建一个 REST API,部署到 Azure 应用服务/Azure API 应用。通过此 API,客户端可以创建“产品”并查询“产品”。产品实体有一组通用字段,所有客户在创建产品时都必须提供这些字段,如下面的字段(示例)
{
"id": "cbf3f7aa-4743-4198-b307-260f703c42c1"
"name": "Product One"
"description": "The number one product"
}
我们目前将这些产品作为独立文档存储在 Azure Cosmos DB 中。
问题 1:分区。 该集合不会存储大量文档,我们谈论最多大约 2 500 000 个文档,每个文档大小在 1 - 5 kb 之间(估计)。我们目前选择了 id 字段(这是我们系统生成的 id,而不是内部 Cosmos DB 文档 id)作为分区键,这意味着 2 500 000 个逻辑分区,每个分区一个文档。这些文档将用于一些低延迟的工作负载,但这些工作负载将通过 id(分区键)进行查询。客户还将通过例如查询名称,然后我们有一个扇出查询,但这些查询不会是延迟关键的。在门户中,您无法再创建单个分区集合,但您可以从 SDK 中创建或使用固定的分区键值。如果我们将所有这些文档放在一个分区中(我们在这里讨论远低于 10 GB 的数据),我们将永远不会得到任何扇出查询,而是更多地依赖于一个逻辑分区中的索引。那么问题来了:即使我们没有海量的数据,像我们目前所做的那样进行分区是否仍然明智?
问题 2:扩展元数据。 我们将面对想要编写超出基本公共字段的客户端/应用程序/客户特定元数据的客户。最好的方法是什么?
下面是我的一些头脑风暴。
1:只需将所有内容转储到一个独立的文档中即可。
一个选项是允许 API 中的客户端在创建产品时添加一种带有键值对的嵌套“扩展元数据”字段。 Cosmos DB 与模式无关,因此理论上这应该可以正常工作。一些产品可以有零扩展元数据,而其他产品可以有很多扩展元数据。对于客户,我们可以承诺基本的公共字段,但对于扩展的元数据字段,我们不能承诺任何关于字段数量、命名等的内容。文档大小会有所不同。如前所述,这些产品仍将用于将通过“id”(分区键“)查询的延迟关键型工作负载。扩展的元数据将永远不会用于任何延迟关键型工作负载。一般会影响文档的程度和方式size the performance/throughput?对于延迟关键的读取场景,查询优化器会直接进入正确的分区,然后使用索引快速检索感兴趣的文档字段。还是整个文档总是独立加载和处理您要查询哪些字段?
{
"id": "cbf3f7aa-4743-4198-b307-260f703c42c1"
"name": "Product One"
"description": "The number one product"
"extendedMetadta" : {
"prop1": "prop1",
"prop2": "prop2",
"propN": "propN"
}
}
扩展元数据仅在某些情况下对从同一 API 中检索有用。然后我们可以这样做:
- api.org.com/products/{id} -- 将始终返回具有基本公共字段的产品
- api.org.com/products/{id}/extended -- 将返回完整文档(基本 + 扩展元数据)
2:拆分文档
一种选择可能是进行某种拆分。如果来自 API 的客户端创建了包含扩展元数据的产品,我们可以实现一些逻辑,如果扩展元数据包含数据,则拆分文档。我想拆分可以通过多种方式完成,下面是头脑风暴。我想拆分文档的主要目标(这需要更多的写入操作工作)是为了获得更好的吞吐量,以防文档大小在这里发挥重要作用(在大多数情况下,客户端可以使用基本的公共字段)。
- 一个只包含基本公共字段的基本文档,一个扩展文档(具有相同的id)包含基本公共字段+扩展元数据(基本公共字段的重复)我们可以添加一个“类型”字段,区分基本文档和扩展文档。如果客户要求扩展,我们只会查询“扩展”类型的文档。
- 一个仅包含基本公共字段的基本文档 + 对仅包含扩展元数据的扩展文档的引用。这意味着客户请求具有扩展元数据的产品的读取操作需要读取两个文档。
- 考虑将其拆分为不同的集合,一个集合包含具有专用于低延迟读取场景的吞吐量的基本文档,另一个集合用于扩展元数据。
抱歉,发了很长的帖子。希望这是可以理解的,期待您的反馈!
【问题讨论】:
标签: json rest azure-cosmosdb document-database