c# - 使用 insertMany 的 CosmosDb 请求率很大
问题描述
我有以下存储库类从批处理中将数据插入 CosmosDb 数据库:
public bool InsertZonierData(List<Zonier> zonierList)
{
if (zonierList == null || !zonierList.Any())
{
throw new ZonierListNullOrEmptyException();
}
else
{
try
{
_collection.InsertMany(zonierList);
return true;
}
catch (MongoBulkWriteException ex)
{
throw new DataBaseWritingException(ex.Message, ExceptionCodeConstants.DataBaseWritingExceptionCode);
}
}
}
不幸的是,在 中有超过 30000 个元素zonierList
,它会在 CosmosDb 上引发以下异常:
未处理的异常:MongoDB.Driver.MongoCommandException:命令插入失败:消息:{“错误”:[“请求率很大”]}
根据文档,这是与 Cosmos 上的 RU / sec 相关的问题。当然,一个简单的方法是增加它,但这不是我想要做的。
是否有一种简单明了的方法来重构该方法,允许我们在不破坏 CosmosDb 的 400 RU / sec 的情况下插入数据。
解决方案
Mongo 驱动程序会告诉您哪些记录出错,哪些根本没有处理。如果所有错误(通常是一个)的代码为 16500,那么您的问题是限制并重试错误并且剩余记录是安全的。否则您的错误是由其他原因引起的,您应该进行分析并决定是否继续重试。
Mongo 驱动程序不会在 Cosmos DB 建议重试前延迟的情况下返回 HTTP 标头,但这没什么大不了的。无论如何,延迟并不能保证成功,因为其他访问同一数据库的请求可能会用完 RU。您最好尝试并确定自己的重试规则。下面是简单的递归解决方案,它会不断重试,直到一切正常或达到重试限制。
private async Task InsertManyWithRetry(IMongoCollection<BsonDocument> collection,
IEnumerable<BsonDocument> batch, int retries = 10, int delay = 300)
{
var batchArray = batch.ToArray();
try
{
await collection.InsertManyAsync(batchArray);
}
catch (MongoBulkWriteException<BsonDocument> e)
{
if (retries <= 0)
throw;
//Check if there were any errors other than throttling.
var realErrors = e.WriteErrors.Where(we => we.Code != 16500).ToArray();
//Re-throw original exception for now.
//TODO: We can make it more sophisticated by continuing with unprocessed records and collecting all errors from all retries.
if (realErrors.Any())
throw;
//Take all records that had errors.
var errors = e.WriteErrors.Select(we => batchArray[we.Index]);
//Take all unprocessed records.
var unprocessed = e.UnprocessedRequests
.Where(ur => ur.ModelType == WriteModelType.InsertOne)
.OfType<InsertOneModel<BsonDocument>>()
.Select(ur => ur.Document);
var retryBatchArray = errors.Union(unprocessed).ToArray();
_logger($"Retry {retryBatchArray.Length} records after {delay} ms");
await Task.Delay(delay);
await InsertManyWithRetry(collection, retryBatchArray, retries - 1, delay);
}
}
推荐阅读
- c# - 从十进制转换为字符串时无用的替换
- python - 有没有办法加快 pd.read_excel() 从 .xlsm 文件中读取的速度?
- git - fortran的git diff中的函数上下文?
- c# - 如何使用 C# 写入一些具有多张工作表的 excel 工作表
- ios - 设置 HKQueryAnchor 时,如何绕过 iOS 12.0 中已弃用的“unarchiveObject(with:)”?
- docker - 使用 gitlab runner 和 gitlab-ci 自动本地部署 docker 容器,无需特权用户
- html - CSS - 背景颜色溢出问题
- python-3.x - 如果版本更改会破坏代码,则支持一个包的多个版本
- tensorflow - Pytorch 相当于 TensorFlow
- java - 如何从“WAMP”中正确删除“mariadb”?