诊断并排除 Azure Cosmos DB for NoSQL .NET SDK 请求超时异常

如果软件开发工具包(SDK)在超时限制发生之前无法完成请求,则会发生 HTTP 408 错误。

请务必确保应用程序设计遵循 我们的指南,了解如何使用 Azure Cosmos DB for NoSQL SDK 设计可复原的应用程序 ,以确保它正确响应不同的网络条件。 应用程序应针对超时错误设置重试机制,因为这些错误通常在分布式系统中是预期的。

评估超时错误的情况时,请考虑以下操作:

  • 衡量受影响操作的数量与成功操作的数量之间的差异。
  • 确定效果是否在服务级别协议中定义的阈值内。
  • 评估 P99 延迟或可用性受到的影响。
  • 确定故障是影响所有应用程序实例还是仅影响子集。

自定义 Azure Cosmos DB for NoSQL .NET SDK 的超时持续时间

SDK 有两种不同的替代方法,用于控制超时,每个选项具有不同的范围。

请求级别超时

CosmosClientOptions.Requesttime out 配置(或 ConnectionPolicy.Requesttime out 用于 SDK v2)允许在请求离开 SDK 并在网络上传输时,为网络请求设置超时,直至收到响应。

CosmosClientOptions.OpenTcpConnectiontime out 配置(对于 SDK v2 可使用 ConnectionPolicy.OpenTcpConnectiontime out)允许您设置打开初始连接所花费时间的超时时间。 打开连接后,后续请求将使用连接。

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

CancellationToken

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

备注

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

故障排除步骤

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

CosmosOperationCanceledException

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

该异常的Message / ToString()不仅通过Cancellation Token has expired: true指示你的CancellationToken状态,还包含Diagnostics,其中包含相关请求取消的上下文。

从重试的角度出发,这些异常是安全的,可以将其视为[超时异常](conceptual-resilient-sdk-applications.md#time outs-and-connectivity-related-failures-http-408503)。

解决方案

核实您CancellationToken中的配置时间。 然后,请确保它大于你的请求超时CosmosClientOptions.OpenTcpConnectionTimeout 属性(如果使用直接模式)。 如果CancellationToken的可用时间小于配置的超时,并且 SDK 面临 [暂时性连接问题](conceptual-resilient-sdk-applications.md#time outs-and-connectivity-related-failures-http-408503),则 SDK 无法重试并引发CosmosOperationCanceledException异常。

CPU 利用率较高

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

超时内容包含 Diagnostics,其中包括:

"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 利用率的来源并降低 CPU 利用率,或将计算机升级到更大的资源配置。
  • 如果 threadInfo/isThreadStarving 节点具有 True 值,原因为线程耗尽。 在这种情况下,解决方案是调查导致线程饥饿的源头(可能是被锁定的线程),或者将机器扩展到更大的资源规模。
  • 如果测量时间间隔不是大约10秒,这也表明线程池上的争用。 CPU 作为独立任务进行度量,该任务每 10 秒排队在线程池中。 如果两次测量之间的时间更长,则表明异步任务不能及时处理完毕。 在应用程序 代码中通过异步代码执行阻止调用 时,通常会发生这种情况。

解决方案

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

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

解决方案在 Azure 中运行时,使用 .NET SDK 的客户端可能会遇到 Azure 网络地址转换(SNAT)端口耗尽问题。

解决方案 1

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

解决方案 2

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

解决方法 3

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

解决方法 4

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

创建多个客户端实例

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

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

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

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

解决方案

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

热分区键

Azure Cosmos DB for NoSQL 将总体预配吞吐量均匀分布到物理分区。 存在热分区时,物理分区上的一个或多个逻辑分区键会消耗物理分区的所有请求单位/秒 (RU/s)。 同时,将无法使用其他物理分区上的 RU/s。 作为症状,消耗的总 RU/s 小于数据库或容器上预配的总 RU/秒,但针对热门逻辑分区键的请求发生限速(429 错误)。 使用 Normalized RU Consumption 指标 查看工作负荷是否遇到热分区。

解决方案

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

并发度较高

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

解决方案

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

大型请求或响应

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

解决方案

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

故障率符合 Azure Cosmos DB for NoSQL 服务级别协议(SLA)的规定

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

失败率违反了 Azure Cosmos DB for NoSQL 服务级别协议

请联系 Azure 支持部门