通过 Azure Cosmos DB SDK 设计可复原的应用程序
适用范围: NoSQL
通过任何 SDK 创作与 Azure Cosmos DB 交互的客户端应用程序时,必须了解一些关键的基础知识。 本文是一个设计指南,可帮助你了解这些基础知识并设计可复原的应用程序。
连接模式
Azure Cosmos DB SDK 可以在两种连接模式下连接到服务。 .NET 和 Java SDK 可以在“网关”和“直接”模式下连接到服务,而其他 SDK 只能在“网关”模式下连接。 “网关”模式使用 HTTP 协议,“直接”模式通常使用 TCP 协议。
“网关”模式始终用于提取元数据(例如帐户、容器和路由信息),无论 SDK 已配置为使用哪种模式。 此信息缓存在内存中,用于连接到服务副本。
总而言之,对于“网关”模式下的 SDK,可以预期 HTTP 流量,而对于“直接”模式下的 SDK,可以预期不同情况(例如初始化、提取元数据或路由信息)下的 HTTP 和 TCP 流量的组合。
客户端实例和连接
无论连接模式如何,为每个应用程序的每个帐户维护 SDK 客户端的单一实例都至关重要。 HTTP 和 TCP 连接都限于该客户端实例。 大多数计算环境在可同时打开的连接数方面都有限制,在达到这些限制时,连接将受到影响。
分布式应用程序和网络
设计分布式应用程序时,有三个关键组件:
- 应用程序及其运行环境。
- 网络,包括应用程序和 Azure Cosmos DB 服务终结点之间的任何组件。
- Azure Cosmos DB 服务终结点。
发生故障时,它们通常属于这三个方面之一,并且你必须了解,由于系统的分布式性质,期望这些组件中的任何一个达到 100% 的可用性是不切实际的。
Azure Cosmos DB 具有一组全面的可用性 SLA,但其中没有一个为 100%。 将应用程序连接到服务终结点的网络组件可能会发生暂时性的硬件问题并丢失数据包。 即使是运行应用程序的计算环境也可能会出现 CPU 峰值,从而影响操作。 这些故障情况可能会影响 SDK 的操作,通常显示为带有特定代码的错误。
通过针对 SDK 提供的响应实施重试策略,应用程序应该能够从这些组件上一定程度的潜在故障中复原。
应用程序应该在出错时进行重试吗?
简短的答案是“是”。 但重试并非在出现任何一种错误时都有意义,某些错误或状态代码不是暂时性的。 下表对这些错误进行了详细说明:
状态代码 | 应添加重试 | SDK 重试 | 说明 |
---|---|---|---|
400 | 否 | 否 | 错误的请求 |
401 | 否 | 否 | 未授权 |
403 | 可选 | 否 | 已禁止 |
404 | 否 | 否 | 找不到资源 |
408 | 是 | 是 | 请求已超时 |
409 | 否 | 否 | 冲突故障是指为某个写入操作的资源提供的标识(ID 和分区键)已被现有资源占用,或者唯一键约束已被违反。 |
410 | 是 | 是 | 丢失异常(不应违反 SLA 的瞬间故障) |
412 | 否 | 否 | 前提条件失败是操作指定的 eTag 与服务器上提供的版本不同。 这是乐观并发错误。 在读取资源的最新版本并更新请求中的 eTag 后重试该请求。 |
413 | 否 | 否 | 请求实体太大 |
429 | 是 | 是 | 针对 429 进行重试很安全。 查看用于排查 HTTP 429 问题的指南。 |
449 | 是 | 是 | 仅在进行写入操作时才发生的暂时性错误,可安全重试。 这可能指向一个设计问题,即有太多并发操作试图更新 Azure Cosmos DB 中的同一对象。 |
500 | 否 | 否 | 操作由于意外服务错误而失败。 通过提交 Azure 支持问题联系支持人员。 |
503 | 是 | 是 | 服务不可用 |
在上表中,第二列中所有标有“是”的状态代码都应该在应用程序中具有某种程度的重试覆盖率。
HTTP 403
Azure Cosmos DB SDK 通常不会针对 HTTP 403 故障进行重试,但你的应用程序可能会决定对与 HTTP 403 关联的某些错误做出反应。 例如,如果收到一条指示分区键已满的错误,你可能会决定根据某种业务规则更改要尝试写入的文档的分区键。
HTTP 429
默认情况下,Azure Cosmos DB SDK 将按照客户端配置并遵循服务的 x-ms-retry-after-ms
响应标头,通过等待指示的时间并在此时间后重试,针对 HTTP 429 错误进行重试。
超过 SDK 重试次数时,错误将返回给应用程序。 理想情况下,检查响应中的 x-ms-retry-after-ms
标头可以用作提示,以决定重试请求之前需要等待多久。 另一种替代方法是指数退避算法或配置客户端以扩展针对 HTTP 429 的重试。
HTTP 449
Azure Cosmos DB SDK 将在固定时段内使用增量退避针对 HTTP 449 进行重试,以适应大多数方案。
超过自动 SDK 重试次数时,错误将返回给应用程序。 可以安全地重试 HTTP 449 错误。 由于写入操作具有高并发性,因此最好使用随机退避算法,以避免在固定间隔后重复相同的并发度。
超时和与连接相关的故障 (HTTP 408/503)
网络超时和连接故障也是最常见的错误。 Azure Cosmos DB SDK 本身具有复原能力,并且会在重试可行的情况下跨 HTTP 和 TCP 协议重试超时和连接问题:
- 对于读取操作,SDK 将重试任何超时或与连接相关的错误。
- 对于写入操作,SDK 将不重试,因为这些操作不是幂等的。 如果在等待响应时发生超时,则无法知道请求是否到达服务。
如果该帐户有多个可用区域,SDK 也会尝试跨区域重试。
由于超时和连接故障的性质,这些信息可能不会出现在帐户指标中,因为它们只涵盖服务端发生的故障。
建议让应用程序拥有自己的适用于这些方案的重试策略,并考虑到如何解决写入超时。 例如,如果上一个请求确实到达了服务,则针对“创建”超时进行重试可能会生成 HTTP 409(冲突),但如果上一个请求未到达该服务,则该重试会成功。
特定于语言的实现详细信息
有关语言的进一步实现详细信息,请参阅:
重试是否会影响延迟?
从客户端的角度来看,任何重试都会影响操作的端到端延迟。 当应用程序 P99 延迟受到影响时,了解正在发生的重试以及如何解决相关问题非常重要。
Azure Cosmos DB SDK 在日志和诊断中提供了详细信息,这些信息可帮助识别正在发生哪些重试。 有关详细信息,请参阅如何收集 .NET SDK 诊断以及如何收集 Java SDK 诊断。
如何减少重试延迟?
大多数情况下,SDK 会将请求路由到本地区域、写入区域(在单区域写入场景中)或首选区域列表中的第一个区域(视具体情形而定)。 此优先顺序通过优先连接到最接近或最佳的数据中心,将正常方案中的延迟降到最低。
但是,此优先顺序还意味着,对于给定的错误方案,将始终先在一个特定区域中尝试失败的请求。 在这种情况下,如果需要将故障转移到另一个区域,则通常在基础结构(流量管理器)层而不是 SDK 级别进行处理。 正确设置和配置基础结构可确保在发生区域性服务中断期间有效地重新路由流量,从而减少中断方案中跨区域重试的延迟。 有关设置基础结构级故障转移的更多详细信息,请参阅 Azure 流量管理器文档。 某些 SDK 支持直接在 SDK 级别实现类似的故障转移策略。 例如,请参阅 Java SDK 的高可用性。
在区域性服务中断方面的影响如何?
Azure Cosmos DB SDK 涵盖区域可用性,可以对其他帐户区域执行重试。 请参阅多区域环境重试方案和配置一文,以了解哪些方案涉及其他区域。
何时联系客户支持
联系客户支持之前,请完成以下步骤:
- 以受影响的操作量与成功的操作量相比作为度量方式所度量出的影响如何? 它是否在服务 SLA 中?
- P99 延迟是否受影响?
- 故障是否与我的应用程序应重试的错误代码有关,应用程序是否涵盖此类重试?
- 故障是影响所有应用程序实例还是仅影响一部分? 当问题缩减到实例的一部分时,这通常就是与这些实例相关的问题。
- 是否浏览了上表中的相关故障排除文档,以排除应用程序环境相关的问题?
如果所有应用程序实例都受到影响,或者受影响操作的百分比超出了服务 SLA 或影响到你自己的应用程序 SLA 和 P99,请联系客户支持。
后续步骤
- 了解多区域环境重试方案和配置
- 查看可用性 SLA
- 使用最新的 .NET SDK
- 使用最新的 Java SDK
- 使用最新的 Python SDK
- 使用最新的 Node SDK