我们在Azure中有一个web应用程序(asp.net core 3.1(,用于查询CosmosDB数据库(具有自动缩放功能(。出于性能原因,我通过首先创建一个Task<data>
数组,然后运行Task.WhenAll(..)
来发送查询,来并行处理所有查询。当数组变得太大(~3000(时,我经常会得到一个SocketException。问题是,这是随机的,因为我从来没有在我的本地开发PC上得到过这个,当它工作时,在Azure中,数据会在几秒钟后返回。
I Application Insights,失败的查询显示为
- 第一个有200个响应,持续时间约为100毫秒
- 然后我可以有一些200个响应,持续4-5秒
- 然后是持续时间约为20秒的故障
我看到人们唯一推荐的CosmosDB客户端设置是这样的:
client = new DocumentClient(
new Uri(..),
Key,
new ConnectionPolicy()
{
ConnectionMode = ConnectionMode.Direct,
ConnectionProtocol = Protocol.Tcp,
IdleTcpConnectionTimeout = new TimeSpan(0, 10, 0, 0)
});
其他哪些设置可能相关?我玩过MaxRequestsPerTcpConnection = 16
、OpenTcpConnectionTimeout = new TimeSpan(0, 1, 0, 0)
和RequestTimeout = new TimeSpan(0, 1, 0, 0)
,但似乎都没有效果。
更新2020-10-24:
连接的数量可能会限制并行连接,但我不知道如何以简单的方式处理这一问题,因为有时查询会运行良好,有时则不然。
然而,解决方案是避免手动并行,并让CosmosDB以任何优化的方式处理这一问题。我写这些并行查询已经很长时间了,这可能是性能和RU/s之间的权衡,因为查询是跨分区的。代码必须处理427个错误,但当我转到自动缩放时,这个错误被删除了。并行代码现在被重写为跨分区,最大并发量=-1,参考并行跨分区查询。
代码方面,第一个查询是:
var query = client.CreateDocumentQuery<MyClass>(
UriFactory.CreateDocumentCollectionUri(db, collection),
new FeedOptions
{
MaxItemCount = -1
})
.Where(q => q.PartitionKey == partitionKey)
.AsDocumentQuery();
我将其添加到每个分区键的任务列表中。
然后是交叉分区:
var partitionKeys = <list of partition keys>;
var query = client.CreateDocumentQuery<MyClass>(
UriFactory.CreateDocumentCollectionUri(db, collection),
new FeedOptions
{
MaxItemCount = -1,
EnableCrossPartitionQuery = true,
MaxDegreeOfParallelism = -1
})
.Where(q => partitionKeys.Contains(q.PartitionKey))
.AsDocumentQuery();
您可能会遇到Azure应用程序服务对同时连接的限制:
每个实例的最大IP连接数取决于实例大小:每个B1/S1/P1V3实例1920个,每个B2/S2/P2V3实例3968个,8064每个B3/S3/P3V3实例
因此,增加实例大小可能会有所帮助。但这需要管理大量的联系,扩大规模并不一定是最好的方法。在SDK中使用批量支持应该有助于整合这些同时连接:
https://devblogs.microsoft.com/cosmosdb/introducing-bulk-support-in-the-net-sdk/