异常处理和重试 - Amazon Neptune

异常处理和重试

在 Neptune 上构建强大的应用程序通常意味着要为意外情况做好准备,尤其是在处理数据库返回的错误时。针对服务器端异常最常用的响应之一是重试失败的操作。虽然重试逻辑对于弹性系统至关重要,但您需要认识到,并非所有错误都应以相同的方式处理。与其依赖一般的重试行为,不如采用深思熟虑的方法来帮助您构建更可靠、更高效的应用程序。

为什么重试逻辑很重要

重试逻辑是分布式应用程序的重要组成部分。网络不稳定、临时资源限制或并发度修改冲突等暂时性问题可能会导致操作失败。在许多情况下,这些故障并不表示永久性问题,可以通过等待并重试来解决。实施可靠的重试策略意味着承认分布式系统中环境不完美的事实,可确保更高的可靠性和连续性,同时减少手动干预的需求。

滥用重试的风险

默认情况下,重试每个错误可能会导致一些意想不到的后果:

  • 争用增加 – 当反复重试因高并发度而失败的操作时,总体争用情况可能会变得更糟。这可能会导致事务失败和性能下降的恶性循环。

  • 资源耗尽 – 滥用重试可能会在客户端和服务器端使用额外的系统资源。这可能会导致节流甚至服务降级。

  • 客户端延迟增加 – 过多的重试会导致客户端应用程序出现严重延迟,尤其是在每次重试都涉及等待时间的情况下。这可能会对用户体验和下游流程产生负面影响。

制定实用的重试策略

要构建弹性且高效的应用程序,请制定针对应用程序可能遇到的特定错误条件量身定制的重试策略。下面的一些注意事项可以指导您制定合适的方法:

  • 识别可重试的错误 – 并非所有异常都应重试。例如,语法错误、身份验证失败或查询无效不应触发重试。Neptune 提供了错误代码和一般建议,可以帮助您了解能够放心重试哪些错误,但您需要实施适合使用案例的逻辑。

  • 实施指数回退 – 对于瞬态错误,请使用指数回退策略逐渐增加重试之间的等待时间。这有助于缓解争用问题并降低出现级联故障的风险。

  • 考虑初始暂停时长 – 如果服务器没有足够的时间释放成功执行查询所需的资源,那么执行第一次重试的速度太快可能会以同样的错误结束。在适当的情况下延长暂停时间可以减少请求浪费和服务器压力。

  • 为回退添加抖动 – 虽然指数回退有效,但如果多个客户端同时失败然后一起重试,它仍然可能会导致同步的重试风暴。添加抖动(回退延迟的一个小随机变化)有助于分散重试尝试,从而减少所有客户端同时重试并导致负载再次激增的几率。

  • 限制重试尝试 – 设置合理的最大重试次数,以防止无限循环和资源耗尽。

  • 监控和调整 – 持续监控应用程序的错误率,并根据需要调整重试策略。如果您注意到某项操作的重试次数太多,请考虑是否可以优化或序列化该操作。

应用场景示例

合适的重试策略取决于故障的性质、工作负载和您观察到的错误模式。下表总结了一些常见的故障场景,以及如何将重试策略注意事项应用于每种情况。下文提供了解释性段落,帮助您了解更多背景信息。

场景

可重试?

回退和抖动

初始暂停

重试限制

监控和调整

执行短时查询时偶尔出现 CME

短时间的回退,添加抖动

短时间(例如 100 毫秒)

关注上升的 CME 率

执行长时查询时频繁出现 CME

较长时间的回退,添加抖动

较长时间(例如 2 秒)

调查并减少争用

执行成本高昂的查询时存在内存限制

长时间的回退

长时间(例如 5-10 秒)

优化查询,如果问题持续存在,则发出警报

执行成本中等的查询时出现超时

也许

中等时间的回退,添加抖动

中等时间(例如 1 秒)

低到中

评估服务器负载和查询设计

场景 1:执行短时查询时偶尔出现 CME

对于在简短的简单更新期间不频繁出现 ConcurrentModificationException 的工作负载,这些错误通常是暂时的,可以放心重试。在第一次重试之前,请使用短时间的初始暂停(例如 100 毫秒)。这个时间允许清除任何短暂的锁定。将其与短时间的指数回退和抖动相结合,以避免同步重试。由于重试的成本较低,因此较高的重试限制是合理的。尽管如此,还是要监控 CME 率,以了解数据中争用增加的任何趋势。

场景 2:执行长时查询时频繁出现 CME

如果应用程序在执行长时查询时频繁出现 CME,则表明存在较严重的争用情况。在这种情况下,从较长时间的初始暂停开始(例如 2 秒),让持有锁定的当前查询有足够的时间完成。使用较长时间的指数回退并添加抖动。限制重试次数,以避免过多的延迟和资源使用。如果争用问题仍然存在,请检查工作负载的模式,并考虑序列化更新或减少并发来解决根本原因。

场景 3:执行成本高昂的查询时存在内存限制

在已知的资源密集型查询期间发生基于内存的错误时,重试才有意义,但只有在长时间的初始暂停(例如 5 到 10 秒或更长时间)之后,才能让服务器释放资源。使用长时间的回退策略并设置较低的重试限制,因为如果不更改查询或工作负载,就不太可能解决重复的失败问题。持续存在的错误应触发警报,并提示相关人员审查查询的复杂性和资源使用情况。

场景 4:执行成本中等的查询时出现超时

执行成本中等的查询时出现超时是一种更加模棱两可的情况。有时,如果超时是由服务器负载临时达到峰值或网络状况造成的,则重试可能会成功。从中等时间的初始暂停(例如 1 秒)开始,让系统有机会恢复。应用中等时间的回退并添加抖动,以避免同步重试。将重试限制保持在低到中等水平,因为重复的超时可能表明查询或服务器容量存在更深层次的问题。监控模式:如果超时频繁,请评估查询是否需要优化,或者 Neptune 集群是否预置不足。

监控和可观测性

监控是重试策略的关键一环。有效的可观测性可以帮助您了解重试逻辑的运行情况,并在工作负载或集群配置中的某些内容需要注意时提供早期信号。

MainRequestQueuePendingRequests

此 CloudWatch 指标跟踪在 Neptune 输入队列中等待的请求数。值上升表示查询正在备份,这可能是争用过度、资源预置不足或重试风暴的迹象。监控此指标可以帮助您发现重试策略何时导致或加剧排队问题,并可以提示您在故障升级之前调整方法。

其他 CloudWatch 指标

其他 Neptune 指标(例如 CPUUtilizationTotalRequestsPerSecond 和查询延迟)提供额外的背景信息。例如,CPU 和 I/O 过高以及队列长度增加,可能表明集群过载,或者查询过大或过于频繁。您可以根据这些指标设置 CloudWatch 警报,提醒您注意异常行为,并帮助您将错误或重试次数的激增与底层资源限制相关联。

Neptune 状态和查询 API

适用于 Gremlin 的 Neptune 状态 API 及其适用于 openCypherSPARQL 的类似 API 可以让您实时查看集群上接受和运行的查询,这对于诊断瓶颈或实时了解重试逻辑的影响非常有用。

通过组合使用这些监控工具,您可以:

  • 检测何时重试会导致排队和性能下降。

  • 确定何时扩展 Neptune 集群或优化查询。

  • 验证重试策略是否能在不掩盖更深层次问题的情况下解决暂时性故障。

  • 接收有关新出现的争用问题或资源耗尽的预警。

主动监控和发出警报对于维持正常的 Neptune 部署至关重要,尤其是在应用程序并发度和复杂性不断增长的情况下。