Skip to content

队列反转-但需要流量控制

队列是任何异步系统的关键元素,因为它们可以反转控制流。由于它们可以重新调整流量,因此它们使我们能够构建在重负载下表现良好的高吞吐量系统。但所有这些魔力都不是免费的:要正常运行,队列需要流量控制。

流量整形

我们可以从一个新的维度来描述队列:时间。速率表示变量随时间变化的一阶导数。因此,消息到达率描述了在指定间隔(例如每秒)内有多少消息到达。该到达率反过来会随时间变化,并有助于描述任何系统的动态行为。例如,到达率的峰值是系统过载的典型原因。此外,到达率增加的速率(二阶导数)定义了系统必须以多快的速度扩展以应对突然的负载峰值。

绘制随时间变化的到达率是描绘队列威力的绝佳方式。队列可以使消息速率曲线趋于平坦,在网络圈中 也称为流量整形。

我们看到左侧消息到达率不均匀,而右侧的处理率则稳定良好。自然,当到达率低于处理率时,队列就会缩小,一旦队列为空,只要到达率低于到达率,处理率就会跟踪到达率。如果到达率超过处理率,队列就会恢复运行。许多现实生活中的队列允许接收方批量处理消息,而不是逐个处理,就是减轻消息负载的一种方式,或者也算是流量控制的一种方式,令消费速率 > 生产速率。

流量整形的一大优势在于,构建和调整处理右侧流量模式的系统比处理左侧流量模式的系统要容易得多。具体来说,对请求进行排队并使用工作池进行处理的系统在重负载下表现得更为优雅:响应时间会增加,但由于处理速率恒定,系统不太可能因自身重量而崩溃。相比之下,同步系统可能会忙于接受新请求,以至于它们不再有资源来处理现有请求。令人遗憾的是,随着负载增加超过某个阈值,系统吞吐量实际上会下降,如图所示。很容易看出这不是一件好事。

这就是为什么队列被广泛尊崇为“缓冲区”,以保护系统免受闪购、营销活动或拒绝服务攻击等嘈杂和尖锐的世界的影响。以高到达率将消息塞入队列不太可能导致系统过载。与此同时,工作人员正以最佳处理速度忙碌。

有些事必须放弃

我们知道系统架构中没有奇迹,队列也是如此。与任何元素一样,队列的容量是有限的。通常,与处理容量(如工作节点)相比,该容量较高,因为存储消息比运行线程更便宜。尽管如此,它是有限的。

即使没有硬性限制,让队列任意增长也可能不是一个好主意。Little的结果 是排队理论的基本方程之一,它提醒我们,平均等待时间等于系统中的客户数量除以到达率。因此,等待时间会随着队列长度的增加而增加(Little 的结果假设系统稳定,到达率不会持续超过处理率)。

长时间的等待会影响用户体验。如果信息(例如产品订单)需要一年时间才能处理,那么这些信息可能就不再有意义了。因此,您的系统可能在技术上可以运行,但它不再能满足用户的期望,这是一个“所有灯都亮起,系统就瘫痪了”的典型例子。

流量控制

为了使排队系统在持续高负载下充分运行,它需要某种形式的流量控制。

维基百科将流量控制的作用描述为:

管理两个节点之间的数据传输速率,以防止快速发送方压倒慢速接收方。

如上所述,队列通过解耦发送方和接收方之间的控制流来提供流量控制。但要有效地做到这一点,它最终需要额外的流量控制。

三种主要机制提供流量控制,以避免队列填充超出其可管理或有用的大小,并保持系统稳定:

  • 生存时间 (TTL):有限的生存时间会从队列中删除旧消息,以便为新消息腾出空间。这种方法非常适合价值随时间推移而下降的消息,例如数据流(2 周前的 CPU 利用率可能不再与警报相关)或客户订单(客户可能会惊讶于他们几周前下的订单竟然得到了处理)。
  • 尾部丢弃则相反,它会丢弃到达的新消息。如果旧消息太有价值而不能丢弃,或者发送者有反馈机制,让他们意识到消息被丢弃,从而允许他们稍后重试,那么这种方法可能是合适的。
  • 背压通知上游系统队列无法处理传入消息,以便这些系统可以降低到达率,例如向用户显示错误消息。

写到这里,其实上述的方式有没有和生活中的一些场景很相似?是的,其实很多应用来源于生活。 例如,热门酒吧的队列(我们曾经等了一个多小时才进入当时在重庆的一家很火爆的酒吧)。客户可能根据自己的时间成本(TTL)来决定是否要继续等待或放弃离开。保镖可能会以根据场地的人员拥堵情况直接赶走到达的顾客。或者他们可能会设置专门的等候区作为反压力的一种形式。当然,甚至你可以类比到以前学习的知识上,例如网络上的数据如何传输,拥塞控制?亦或分包分块?

速率限制:主动流量整形

背压、TTL 和尾部丢弃相当于一个压力释放阀,一旦事情即将爆发,它们就会启动。当您设计一个接收消息的系统时,您可能提前知道它的极限,并避免不得不退缩。这就是为什么许多云系统都有明确的选项来限制推送传递的传递率。在某种程度上,您正在施加持续的背压来限制消息到达的速度。

小结

消息中间件是我们系统重常用的一个组件,上面只是简要的描述了消息队列的一些特性,如今有许多开源受欢迎的MQ,如RocketMq、kafka、RabbitMQ等等。我想说的是,具体场景具体应用,同时做到知其然知其所以然,而不是盲目的使用这些技术栈...

Released under the MIT License.