系统设计》课程学习笔记—消息队列

218 阅读4分钟

消息队列是一种便于异步通信的服务对服务通信形式。它异步接收来自生产者的消息并将其发送给消费者。

队列用于有效管理大规模分布式系统中的请求。在具有最小处理负载和小型数据库的小型系统中,写入速度可以预见。然而,在更为复杂的大型系统中,写入需要的时间可能不确定。

message-queue.webp

工作方式

消息存储在队列中,直到它们被处理和删除。每个消息仅由单个消费者处理一次。它的工作原理如下:

  • 生产者将作业发布到队列,然后通知用户作业状态。
  • 消费者从队列中提取作业,对其进行处理,然后发出作业完成的信号。

优点

让我们讨论使用消息队列的一些优点:

  • 可扩展性(Scalability):消息队列可以精确地扩展到我们需要的程度。当工作负载达到峰值时,我们应用程序的多个实例都可以将请求添加到队列中,而不用担心发生冲突。
  • 解耦(Decoupling):消息队列移除了组件之间的依赖关系,并显著简化了解耦应用程序的实现。
  • 性能(Performance):消息队列支持异步通信,这意味着生成和使用消息的端点与队列交互,而不是彼此交互。生产者可以将请求添加到队列中,而无需等待处理。
  • 可靠性(Reliability):队列使我们的数据持久化,并减少系统不同部分脱机时发生的错误。

特征

现在,让我们讨论消息队列的一些特征:

推拉式传输

大多数消息队列都提供了用于取出消息的推送和拉取选项。拉取意味着持续查询队列中的新消息。推送意味着当消息可用时通知消费者。我们还可以使用长轮询来允许拉取等待指定的时间,以等待新消息到达。

FIFO(先进先出)队列

在这些队列中,最早的(或第一个)消息(有时称为队列的“头”)首先被处理。

计划或延迟传输

许多消息队列支持为消息设置特定的传输时间。如果我们需要为所有消息设置一个公共延迟,我们可以设置一个延迟队列。

至少一次传输

消息队列可以存储消息的多个副本,以实现冗余和高可用性,并在通信失败或错误的情况下重新发送消息,以确保它们至少传输一次。

仅一次传输

当不能容忍重复时,FIFO(先进先出)消息队列将通过自动过滤重复消息来确保每个消息准确传输一次(且仅传输一次)。

死信队列

死信队列(Dead-letter Queues)是其他队列可以向其发送无法成功处理的消息的队列。这样可以很容易地将它们放在一边进行进一步的检查,而不会阻塞队列处理或在可能永远不会成功使用的消息上浪费CPU周期。

排序

大多数消息队列提供尽力而为的排序,确保消息通常以与发送相同的顺序传递,并且消息至少传递一次。

毒丸消息

毒丸消息(Poison-pill Messages)是可以接收但不能处理的特殊消息。它们是一种机制,用于向消费者发出结束工作的信号,使其不再等待新的输入,类似于客户端/服务器模型中的关闭套接字。

安全

消息队列将对尝试访问队列的应用程序进行身份验证,这允许我们对网络上以及队列本身中的消息进行加密。

任务队列

任务队列接收任务及其相关数据,运行它们并交付结果。它们可以支持调度,并可用于在后台运行的计算密集型作业。

背压(Backpressure)

如果队列开始显著增长,队列大小可能会变得大于内存,从而导致缓存未命中,改为磁盘读取,导致性能降低。背压可以通过限制队列大小使队列中已经存在的作业保持高吞吐量和良好的响应时间。队列填满后,客户端会收到服务器忙或 HTTP 503 状态码,以便稍后重试。客户端可能采用指数退避策略来在稍后重试请求。

例子

以下是一些广泛使用的消息队列: