内容提要
Canva为队列worker引入“Worker Backpressure”机制,根据依赖调用成败动态调节并发:失败时自动减速,恢复后自行提速,无需人工干预。该机制已在两次生产故障中生效,避免了DLQ消息堆积和告警,保障了服务稳定。
延伸解读
为何需要 Worker Backpressure
Canva 的异步架构中,worker 会贪婪地拉取消息并调用依赖。当依赖开始失败时,这种贪婪行为会持续施压,导致失败消息堆积到 DLQ,甚至引发严重故障。传统方案如手动扩缩容、固定限流、熔断器和指数退避各有局限,无法在多样化的队列场景中自适应。Worker Backpressure 通过动态调节并发,在依赖健康时全速运行,在失败时自动减速,从而保护依赖并减少人工干预。
机制如何工作
Backpressure 是一个反馈循环,跟踪每次依赖调用的成功或失败,并据此调节 worker 的并发数。它完全在本地运行,无需外部协调器或额外网络调用,运行时开销仅两次算术运算。当依赖健康时,backpressure 不干预;当错误率上升时,它降低并发,减少对依赖的压力和无效尝试。这种设计简单且可扩展,未来可加入延迟等更多信号。
生产环境中的实战验证
Backpressure 已在两次生产事故中证明有效。第一次是云提供商故障导致依赖间歇性失败,worker 自动减速,DLQ 仅增加一条消息,无人被呼叫。第二次是持续过载,worker 推送消息到有配额限制的队列,backpressure 将失败率控制在设定点以下,DLQ 缓慢增长而非爆炸。两次事故中,backpressure 都成功遏制了故障影响,避免了人工干预。
权衡与未来方向
Backpressure 以吞吐量换取错误率降低,对于有余量的 worker 影响不大,但满负荷的 worker 会感受到成本。当前仅使用成功/失败作为依赖健康的代理信号,可能不适用于所有工作负载。团队计划将其推广到所有队列 worker,并探索更多信号和调优参数。第二部分将深入控制器细节和模拟测试。
Q&A
Canva 的 Worker Backpressure 是什么?
Worker Backpressure 是 Canva 为队列 worker 引入的一种可靠性机制,它根据 worker 对依赖调用的成败动态调节并发数:失败时自动减速,恢复后自行提速,无需人工干预。
为什么 Canva 要构建 Worker Backpressure?
因为 worker 通常是贪婪的,会不断拉取消息并调用依赖。当依赖开始失败时,贪婪的 worker 会继续全速拉取,导致依赖被进一步压垮、失败消息堆积到 DLQ、服务降级并触发告警。Canva 需要一种能自动调节 worker 速度的机制来保护依赖并维持服务稳定。
Worker Backpressure 是如何工作的?
Backpressure 是一个围绕 worker 调用依赖的反馈循环。它跟踪每次调用的结果作为依赖健康信号,并调节 worker 的并发数(同时处理的消息数)。依赖健康时,backpressure 不干预;依赖挣扎时,它限制 worker 的速度。整个过程在本地进行,无需外部协调器或额外网络调用。
Worker Backpressure 在真实故障中表现如何?
它已在两次生产故障中生效。第一次是云提供商中断导致约 4 小时间歇性错误尖峰,backpressure 使 worker 减速,DLQ 深度几乎未变,无人被呼叫。第二次是持续 32.5 小时的过载,backpressure 将失败率控制在设定点以下,DLQ 仅缓慢增长。两次都自动减速并在恢复后提速。
Worker Backpressure 有哪些设计上的权衡?
Backpressure 会降低错误率,但也会牺牲吞吐量。在两次故障中,worker 有足够余量吸收减速,但满负荷运行的 worker 会感受到成本。此外,控制器仅依赖成功/失败这一单一信号作为依赖健康的代理,可能不适用于所有工作负载,但控制器可扩展,未来可加入延迟等更多信号。
Worker Backpressure 与熔断器、指数退避等方案有何不同?
熔断器在错误超阈值时完全停止流量,没有渐进过渡,恢复时可能再次压垮依赖;指数退避作用于单个消息的重试,不调节整体速率;自适应退避在调用点丢弃部分请求,但 Canva 已有的实现固定于一种算法且不在共享队列库中。Worker Backpressure 是内置于队列库的通用自适应方案,根据调用结果动态调节并发,实现渐进式减速和恢复。