诊断和排查 Azure Cosmos DB .NET SDK 请求超时异常

适用范围: NoSQL

如果 SDK 在超时限制发生之前未能完成请求,则会出现 HTTP 408 错误。

应用程序设计必须遵循我们的使用 Azure Cosmos DB SDK 设计可复原应用程序指南,以确保它正确响应不同的网络条件。 应用程序应对超时错误进行重试,因为分布式系统中通常会遇到这些错误。

在评估超时错误的情况时:

  • 以受影响的操作量与成功的操作量相比作为度量方式所度量出的影响如何? 它是否在服务 SLA 中?
  • P99 延迟/可用性是否受影响?
  • 故障是影响所有应用程序实例还是仅影响一部分? 当问题缩减到实例的一部分时,这通常就是与这些实例相关的问题。

在 Azure Cosmos DB .NET SDK 中自定义超时

该 SDK 提供了两个不同选择来用于控制超时,每个都有不同的作用域。

请求级别超时

通过 CosmosClientOptions.RequestTimeout(对于 SDK v2,则为 ConnectionPolicy.RequestTimeout)配置,你可以为网络请求设置超时(即请求离开 SDK 之后,在网络中传输,直到收到响应)。

通过 CosmosClientOptions.OpenTcpConnectionTimeout(对于 SDK v2,则为 ConnectionPolicy.OpenTcpConnectionTimeout)配置,你可以为打开初始连接所用的时间设置超时。 打开连接后,后续请求将使用该连接。

用户发起的操作可跨多个网络请求(例如重试)。 这两种配置是针对每个请求的,而不是操作的端到端配置。

CancellationToken

SDK 中的所有异步操作都有一个可选的 CancellationToken 参数。 此 CancellationToken 参数将在整个操作过程中跨所有网络请求和重试进行使用。 在网络请求的间隔期间,可能会检查取消令牌;如果相关令牌已过期,则会取消操作。 应使用取消令牌来定义操作范围上的近似预期超时。

注意

CancellationToken 参数是一种机制,其中库将在它不会导致无效状态时检查取消情况。 当在取消中定义的时间已超过时,操作可能无法完全取消。 而在该时间超过后,它会在可安全执行时取消。

疑难解答步骤

下面的列表包含请求超时异常的已知原因和解决方案。

CosmosOperationCanceledException

当应用程序将 CancellationTokens 传递给 SDK 操作时,这种类型的异常很常见。 SDK 检查两次重试之间 CancellationToken 的状态,如果 CancellationToken 取消,它将中止当前操作,但出现此异常。

异常的 Message / ToString() 还将指示你的 CancellationTokenCancellation Token has expired: true 的状态,它还将包含包含所涉及请求的取消上下文的诊断

这些异常可以安全地重试,并且从重试的角度来看可以被视为超时

解决方案

验证 CancellationToken 中配置的时间,确保它大于 RequestTimeoutCosmosClientOptions.OpenTcpConnectionTimeout(如果使用直接模式)。 如果 CancellationToken 中的可用时间小于配置的超时时间,并且 SDK 面临瞬时连接问题,则 SDK 将无法重试并引发 CosmosOperationCanceledException

CPU 利用率较高

最常见的情况是 CPU 利用率较高。 为实现最佳延迟,CPU 利用率应大约为 40%。 将时间间隔设为 10 秒来监视最大 CPU 利用率(而不是平均利用率)。 对于可能会为单个查询执行多个连接的跨分区查询,更常见的情况是出现 CPU 峰值。

超时将包含“诊断”,其中包含:

"systemHistory": [
{
"dateUtc": "2021-11-17T23:38:28.3115496Z",
"cpu": 16.731,
"memory": 9024120.000,
"threadInfo": {
"isThreadStarving": "False",
....
}

},
{
"dateUtc": "2021-11-17T23:38:28.3115496Z",
"cpu": 16.731,
"memory": 9024120.000,
"threadInfo": {
"isThreadStarving": "False",
....
}

},
...
]
  • 如果 cpu 值超过 70%,则超时可能是由于 CPU 耗尽导致的。 在这种情况下,解决方法是调查 CPU 利用率较高的源并使其减少,或将计算机扩展到更大的资源大小。
  • 如果 threadInfo/isThreadStarving 节点具有 True 值,原因为线程耗尽。 在这种情况下,解决方法是调查线程不足(可能锁定的线程)的源,或将计算机扩展到更大的资源大小。
  • 如果两次度量之间的 dateUtc 时间不是大约 10 秒,则它还会指示线程池发生争用。 CPU 作为独立任务进行度量,该任务每隔 10 秒在线程池中排队一次。如果两次度量之间的时间延长,则表明异步任务无法及时处理。 最常见的场景是在应用程序代码中进行基于异步代码的阻止调用

解决方案

应纵向扩展或横向扩展使用 SDK 的客户端应用程序。

套接字或端口可用性可能较低

使用 .NET SDK 的客户端在 Azure 中运行时,可能会遇到 Azure SNAT (PAT) 端口耗尽问题。

解决方案 1

如果正在 Azure VM 上运行,请按照 SNAT 端口耗尽指南操作。

解决方案 2

如果正在 Azure 应用服务上运行,请按照连接错误故障排除指南使用应用服务诊断操作。

解决方法 3

如果正在 Azure Functions 上运行,请验证是否遵循 Azure Functions 建议,即是否为所有涉及的服务(包括 Azure Cosmos DB)维护单一实例或静态客户端。 根据函数应用托管的类型和大小查看服务限制

解决方法 4

如果使用 HTTP 代理,请确保它支持 SDK ConnectionPolicy 中配置的连接数。 否则将遇到连接问题。

创建多个客户端实例

创建多个客户端实例可能会导致连接争用和超时问题。 诊断包含两个相关属性:

{
    "NumberOfClientsCreated":X,
    "NumberOfActiveClients":Y,
}

NumberOfClientsCreated 跟踪 CosmosClient 在同一 AppDomain 中被创建的次数,而 NumberOfActiveClients 则跟踪活动(即未释放的)客户端。 预期是,如果遵循单一实例模式,则 X 将匹配应用程序使用的帐户数,并且 X 等于 Y

如果 X 大于 Y,则表示应用程序正在创建和释放客户端实例。 这可能会导致连接争用和/或 CPU 争用

解决方案

遵循性能提示,并在整个过程中使用每个帐户的单个 DocumentClient 实例。 避免创建和释放客户端。

热分区键

Azure Cosmos DB 在物理分区之间均匀分配预配的总吞吐量。 存在热分区时,物理分区上的一个或多个逻辑分区键会消耗物理分区的所有请求单位/秒 (RU/s)。 同时,将无法使用其他物理分区上的 RU/s。 故障表现是,所消耗的 RU/s 总数将小于数据库或容器上整体预配的 RU/s,但针对热逻辑分区键仍将显示请求限制 (429s)。 使用规范化 RU 使用量指标来查看工作负载是否遇到热分区。

解决方案

选择均匀分配请求量和存储的适当分区键。 了解如何更改分区键

并发度较高

应用程序正在执行高级别的并发,这可能会导致通道上出现争用。

解决方案

应纵向扩展或横向扩展使用 SDK 的客户端应用程序。

大型请求或响应

较大的请求或响应可能导致通道上出现队头阻塞并加剧资源争用(甚至在并发度相对较低的情况下)。

解决方案

应纵向扩展或横向扩展使用 SDK 的客户端应用程序。

失败率在 Azure Cosmos DB SLA 范围之内

应用程序应该能够处理暂时性故障,并在必要时重试。 任何 408 异常不会被重试,因为在创建路径时不可能知道服务是否创建了该项。 再次发送相同的项进行创建将导致冲突异常。 用户应用程序业务逻辑可能包含用于处理冲突的自定义逻辑,这会消除现有项的不确定性与来自“创建”重试的冲突。

失败率与 Azure Cosmos DB SLA 不符

请联系 Azure 支持部门

后续步骤