CosmosDb 在更新数千个项目期间抛出 429 个请求
CosmosDb throws 429 Requests during updates of thousands of items
我是 CosmosDb 的新手,但很快我就遇到了一个在使用 MS 时从未遇到过的问题 SQL。
目前我们有一个操作,在此期间我们以 100 万个为批次更新数百万个 CosmoDb 项目。在此操作期间,我注意到 App insights 中大约 25% 的请求显示为 429ns。根据 Microsoft documentation 429 个请求中有 1-5% 是健康的,超过这个数就是一个问题。
现在我尝试了不同的方法来降低这个数字而不必扩展吞吐量,但没有任何帮助。我不确定这是否是我的测试实现的问题,因为我尝试了不同的东西并且可能在某处犯了错误。
测试设置:
- 具有 5 个不同容器的数据库。他们每个人都单独缩放。测试 运行 的容器具有 3000 RU/s 最大吞吐量
的自动缩放
- 容器有大约 17 万个资产,大小为 0.5 Gb
- CosmosClient 是单例
- 测试期间要更新 3000 项,每批 1000 项
沐浴操作密码:
var updateTasks = new List<Task>();
// queriedItems will have 1000 items in each batch
foreach (SomeCosmosbDbModel queriedItem in queriedItems)
{
queriedItem.SomeProperty = someValue;
updateTasks.Add(_repository.UpdateAsync(queriedItem));
}
await Task.WhenAll(updateTasks);
更新方法代码:
public Task UpdateAsync(TModel model)
{
return Container.ReplaceItemAsync(model,
model.Id,
new PartitionKey(model.Partition),
new ItemRequestOptions { EnableContentResponseOnWrite = false });
}
以下是我尝试降低 429ns 数量的方法和得到的结果:
- 使用补丁而不是更新操作。我认为它应该比更新操作轻一点 -> 429s 的百分比没有差异
- 正在检查分区键是否有问题。如果我正确理解如果数据库很小并且 RU/s 的数量低于 10.000,分区是如何工作的,那么它应该不会影响这个测试 - doc
- 使用 BulkUpdate 方法 -> 类似数字 429ns。它还导致了一些 FailedReindexExceptions with TooManyRequests (429) 错误,在这种情况下,一些项目实际上没有得到更新(大约 8%)
- 将项目索引更改为 none -> 对 429ns 没有影响
现在看来,所做的所有更改都可以提高操作速度,但每次都达到容器上 RU 的限制,在某些情况下,它实际上导致不执行某些写入操作并抛出异常。
我可以做些什么来降低 429ns 的数量吗?或者如果我在测试期间没有犯错,也许我应该仔细检查我已经尝试过的一些事情?是否还使用推荐用于生产应用程序的自定义 RetryPolicy 来提高弹性?
更新需要一定数量的 RU,您几乎无法控制(索引策略除外)。因此,要减少 429 的数量,您唯一的选择就是降低吞吐量。
如果这是你在那一刻在数据库上的唯一工作负载 运行 我不会太担心它抛出 429,只要你的 RetryPolicy
能够经常和长时间尝试足够了,直到它最终起作用。从理论上讲,您的重试策略应该能够处理在开始和上传所有其他文档的过程中失败的请求;因此,您的 RetryPolicy
应该包括大量重试和超过上传批次所需的最长时间的超时。
如果其他进程也在使用您的数据库,那么最好考虑限制您发送的请求数量,这更复杂但也是可行的。每个响应都包含使用的 RU,这使您可以通过在请求之间添加 Task.Delay(...)
来非常精确地调整吞吐量。
我不会太担心 1-5% 的提示。这主要针对平均数据库使用情况,而不是批量导入。
我是 CosmosDb 的新手,但很快我就遇到了一个在使用 MS 时从未遇到过的问题 SQL。
目前我们有一个操作,在此期间我们以 100 万个为批次更新数百万个 CosmoDb 项目。在此操作期间,我注意到 App insights 中大约 25% 的请求显示为 429ns。根据 Microsoft documentation 429 个请求中有 1-5% 是健康的,超过这个数就是一个问题。
现在我尝试了不同的方法来降低这个数字而不必扩展吞吐量,但没有任何帮助。我不确定这是否是我的测试实现的问题,因为我尝试了不同的东西并且可能在某处犯了错误。
测试设置:
- 具有 5 个不同容器的数据库。他们每个人都单独缩放。测试 运行 的容器具有 3000 RU/s 最大吞吐量 的自动缩放
- 容器有大约 17 万个资产,大小为 0.5 Gb
- CosmosClient 是单例
- 测试期间要更新 3000 项,每批 1000 项
沐浴操作密码:
var updateTasks = new List<Task>();
// queriedItems will have 1000 items in each batch
foreach (SomeCosmosbDbModel queriedItem in queriedItems)
{
queriedItem.SomeProperty = someValue;
updateTasks.Add(_repository.UpdateAsync(queriedItem));
}
await Task.WhenAll(updateTasks);
更新方法代码:
public Task UpdateAsync(TModel model)
{
return Container.ReplaceItemAsync(model,
model.Id,
new PartitionKey(model.Partition),
new ItemRequestOptions { EnableContentResponseOnWrite = false });
}
以下是我尝试降低 429ns 数量的方法和得到的结果:
- 使用补丁而不是更新操作。我认为它应该比更新操作轻一点 -> 429s 的百分比没有差异
- 正在检查分区键是否有问题。如果我正确理解如果数据库很小并且 RU/s 的数量低于 10.000,分区是如何工作的,那么它应该不会影响这个测试 - doc
- 使用 BulkUpdate 方法 -> 类似数字 429ns。它还导致了一些 FailedReindexExceptions with TooManyRequests (429) 错误,在这种情况下,一些项目实际上没有得到更新(大约 8%)
- 将项目索引更改为 none -> 对 429ns 没有影响
现在看来,所做的所有更改都可以提高操作速度,但每次都达到容器上 RU 的限制,在某些情况下,它实际上导致不执行某些写入操作并抛出异常。
我可以做些什么来降低 429ns 的数量吗?或者如果我在测试期间没有犯错,也许我应该仔细检查我已经尝试过的一些事情?是否还使用推荐用于生产应用程序的自定义 RetryPolicy 来提高弹性?
更新需要一定数量的 RU,您几乎无法控制(索引策略除外)。因此,要减少 429 的数量,您唯一的选择就是降低吞吐量。
如果这是你在那一刻在数据库上的唯一工作负载 运行 我不会太担心它抛出 429,只要你的 RetryPolicy
能够经常和长时间尝试足够了,直到它最终起作用。从理论上讲,您的重试策略应该能够处理在开始和上传所有其他文档的过程中失败的请求;因此,您的 RetryPolicy
应该包括大量重试和超过上传批次所需的最长时间的超时。
如果其他进程也在使用您的数据库,那么最好考虑限制您发送的请求数量,这更复杂但也是可行的。每个响应都包含使用的 RU,这使您可以通过在请求之间添加 Task.Delay(...)
来非常精确地调整吞吐量。
我不会太担心 1-5% 的提示。这主要针对平均数据库使用情况,而不是批量导入。