Azure Cosmos DB 的重写分区键策略

Write-heavy partition key strategy for Azure Cosmos DB

我们在生产中使用 CosmosDB 来存储 HTTP request/response 审计数据。该数据的结构大致如下:

{
    "id": "5ff4c51d3a7a47c0b5697520ae024769",
    "Timestamp": "2019-06-27T10:08:03.2123924+00:00",
    "Source": "Microservice",
    "Origin": "Client",
    "User": "SOME-USER",
    "Uri": "GET /some/url",
    "NormalizedUri": "GET /SOME/URL",
    "UserAgent": "okhttp/3.10.0",
    "Client": "0.XX.0-ssffgg;8.1.0;samsung;SM-G390F",
    "ClientAppVersion": "XX-ssffgg",
    "ClientAndroidVersion": "8.1.0",
    "ClientManufacturer": "samsung",
    "ClientModel": "SM-G390F",
    "ResponseCode": "OK",
    "TrackingId": "739f22d01987470591556468213651e9",
    "Response": "[ REDACTED ],   <— Usually quite long (thousands of chars)
    "PartitionKey": 45,
    "InstanceVersion": 1,
    "_rid": "TIFzALOuulIEAAAAAACACA==",
    "_self": "dbs/TIFzAA==/colls/TIFzALOuulI=/docs/TIFzALOuulIEAAAAAACACA==/",
    "_etag": "\"0d00c779-0000-0d00-0000-5d1495830000\"",
    "_attachments": "attachments/",
    "_ts": 1561630083
}

我们目前每天编写大约 150,000 - 200,000 个与上述类似的文档,其中 /PartitionKey 作为在容器上配置的分区键路径。 PartitionKey 的值是 C#.net 中随机生成的一个数字,介于 0 和 999 之间。

但是,我们看到日常热点中单个物理分区最多可以达到 2.5K - 4.5K RU/s,而其他的非常低(大约 200 RU/s)。这会影响成本,因为我们需要为最大的使用分区提供吞吐量。

第二个因素是我们要存储相当多的数据,接近 1TB 的文档,而且我们每天都会增加几 GB。因此,我们目前有大约 40 个物理分区。

结合这两个因素意味着我们最终必须至少准备 120,000 - 184,000 RU/s。

我应该提一下,我们几乎不需要查询这些数据;除了偶尔在 Cosmos 数据资源管理器中临时手动构建的查询。

我的问题是...通过简单地使用“id”列作为我们的分区键(或随机生成的 GUID),我们在 RU/s 要求和数据分布方面会更好吗- 然后设置合理的 TTL,这样我们就没有持续增长的数据集?

我知道这需要我们重新创建集合。

非常感谢。

Max throughput per physical partition

虽然使用 id 或 GUID 会比现在的随机数提供更好的基数,但您 运行 的任何查询都将非常昂贵,因为它总是跨分区且数量巨大数据。

我认为更好的选择是使用组合多个属性的合成键,这些属性既具有高基数又用于查询数据。可以在这里了解更多信息,https://docs.microsoft.com/en-us/azure/cosmos-db/synthetic-partition-keys

就 TTL 而言,我肯定会将其设置为您需要保留此数据的任何时间。 Cosmos 将使用未使用的吞吐量关闭数据,因此永远不会妨碍。

最后,您还应该考虑(如果您还没有)使用自定义索引策略并排除任何从未被查询过的路径。特别是 "response" 属性 因为你说它有数千个字符长。这可以在像您这样的写入密集型场景中节省大量 RU/s。

根据我的经验,我发现 cosmos 会随着新数据而退化。更多的数据意味着更多的物理分区。因此,您需要将更多的吞吐量分配给它们中的每一个。目前我们开始将旧数据归档到 blob 存储中,以避免此类问题并保持物理分区数量不变。我们使用 cosmos 作为热存储,然后旧数据去 blobs 存储作为冷存储。我们减少了分配给每个物理分区的 RU,从而节省了资金。