RabbitMQ 是一个功能强大且广泛使用的消息代理,它通过处理消息的传输、存储和交付来促进分布式应用程序之间的通信。作为消息代理,RabbitMQ 充当生产者(发送消息的应用程序)和使用者(接收消息的应用程序)之间的中介,即使在复杂的分布式环境中也能确保可靠的消息传递。
RabbitMQ 的核心组件之一是队列,消息在其中临时存储,直到被使用。队列在 RabbitMQ 的架构中起着关键作用,支持异步通信并将生产者和使用者解耦。这种解耦允许应用程序独立运行,从而提高可扩展性、弹性和容错能力。
了解 RabbitMQ 中不同类型队列的性能特征对于设计高效的系统架构至关重要。队列决定了消息的路由、存储和使用方式,从而影响吞吐量、延迟和持久性。
了解经典队列
RabbitMQ 中的经典队列是默认队列类型,旨在实现高吞吐量和简单性。它们遵循先进先出 (FIFO) 模型,其中消息按照接收顺序传送给使用者,从而确保可预测的消息流。Classic 队列广泛用于性能和速度比跨多个节点的容错和消息持久性更重要的场景。
Classic Queues 的主要功能
- 单节点存储:Classic 队列存储在单个 RabbitMQ 节点上。消息不会在其他节点之间复制,从而使队列更快,但在节点发生故障时弹性较差。
- FIFO 消息处理:消息按照其到达的顺序进行存储和使用,从而确保简单的处理模型,尤其是对于消息顺序很重要的任务。
- 持久和非持久消息:Classic 队列可以将消息存储在内存中(瞬态)或磁盘(持久)中。持久性消息将保存到磁盘,确保在服务器重新启动或崩溃时消息不会丢失,尽管这会带来性能权衡。
- 高吞吐量:Classic 队列针对速度进行了优化,可以以低延迟处理大量消息。它们最适合消息处理速度至关重要的应用程序,例如实时系统或日志聚合服务。
- 单节点持久性:虽然 Classic 队列支持消息持久性,但它们缺乏跨节点复制。这意味着,如果托管队列的节点发生故障,持久消息将在节点恢复时继续存在,但没有内置冗余来继续跨其他节点进行操作。
Classic 队列的使用案例
- 实时系统:Classic 队列非常适合需要高速消息处理的应用程序,例如游戏系统、流媒体平台或监控工具。
- 无状态应用程序:不需要消息复制或跨节点高可用性的应用程序受益于 Classic 队列的简单性和性能。
- 低延迟:对于需要最大限度地减少消息生成和使用之间的延迟的工作负载,经典队列提供低延迟消息传递。
了解 Quorum 队列
RabbitMQ 中的仲裁队列是一种更新的、高度可用的、具有容错能力的队列类型,专为需要强大的持久性保证和节点故障弹性的系统而设计。Quorum 队列利用 Raft 共识算法跨多个节点复制消息,确保即使在硬件或软件故障的情况下也能保持消息可用性。这使它们非常适合消息丢失或停机不可接受的关键应用程序。
Quorum 队列的主要功能
- 领导-追随者复制:仲裁队列使用领导-追随者模型运行。每个 Quorum 队列都有一个负责处理传入消息的领导节点和多个复制领导消息的 follower 节点。此复制可确保数据冗余,只有在大多数节点 (仲裁) 确认复制后才会确认消息。
- Raft 共识算法:Raft 算法保证了节点之间的一致性。当消息发送到仲裁队列时,它会被复制到关注者,只有在大多数 (仲裁) 关注者确认该消息后,它才会变为 “已提交”。这提供了强大的持久性保证,确保系统可以从故障中恢复而不会丢失数据。
- 容错能力:Quorum 队列旨在承受节点故障。如果 Leader 节点崩溃,将使用 Raft 协议从从 Follower 中选出一个新的 Leader,从而允许消息处理继续进行,并将中断降至最低。这提供了高可用性,并使仲裁队列在分布式环境中具有弹性。
- 消息持久性:默认情况下,仲裁队列中的所有消息都是持久性的,这意味着它们将写入磁盘并在多个节点之间复制。这可确保消息不会丢失,即使 RabbitMQ 集群遇到节点故障或重新启动也是如此。
- 高可用性:Quorum 队列通过确保只要大多数节点正常运行,消息传输和使用就可以继续进行,从而优先考虑可用性。这使它们成为无法容忍停机或数据丢失的任务关键型系统的理想选择。
- 无单点故障:与 Classic 队列不同,Classic 队列由于驻留在单个节点上而容易受到节点故障的影响,而 Quorum 队列通过在 RabbitMQ 集群中的多个节点之间分发消息来消除单点故障的风险。
仲裁队列的使用案例
- 金融服务:处理交易、付款或敏感财务数据的系统受益于 quorum 队列提供的容错能力和消息持久性。这些系统无法承受丢失消息或经历停机的后果。
- 任务关键型应用程序:需要持续运行时间且不能容忍消息丢失的应用程序,例如医疗保健系统、实时监控或工业控制系统,非常适合仲裁队列。
- 分布式系统:在服务器可能发生故障的多节点或分布式环境中,仲裁队列可确保消息处理无缝继续,即使单个节点出现故障也是如此。
性能基准测试:Classic 与 Quorum
我们使用 RabbitMQ PerfTest 工具来评估经典队列和仲裁队列的性能。作为此分析的一部分,我们收集了三种不同场景的性能统计数据。每个场景都涉及发布者和使用者的不同组合,具有固定的消息大小和一致的 30 秒时间间隔。
经典队列性能
场景 |
发送速率 (MSG/S) |
接收速率(MSG/S) |
第 99 个百分位延迟(以微秒为单位) |
场景 1 (1Publisher, 1Consumer) |
13329 |
9897 |
20649010 微秒 |
方案 2 (1Publisher, 2Consumer) |
14112 |
9573 |
21415269 微秒 |
方案 3(2Publisher、4Consumer) |
21829 |
13577 |
27186651 微秒 |
平均值(全部) |
16423 |
10349 |
23083643 微秒 |
仲裁队列性能
场景 |
发送速率 (MSG/S) |
接收速率(MSG/S) |
第 99 个百分位延迟(以微秒为单位) |
场景 1 (1Publisher, 1Consumer) |
9202 |
5581 |
37644181 微秒 |
方案 2 (1Publisher, 2Consumer) |
10717 |
5368 |
29972278 微秒 |
方案 3(2Publisher、4Consumer) |
13132 |
4505 |
32919489 微秒 |
平均值(全部) |
11017 |
5151 |
33,511,316 微秒 |
从执行的测试中获得的见解
1. 吞吐量(发送和接收速率)
- 经典队列:
- 平均发送速率:16,423 msg/s(比 quorum 队列高 49%)
- 平均接收速率:10349 msg/s(比 quorum 队列高 2 倍)
- 仲裁队列:
- 平均发送速率:11,017 msg/s
- 平均接收速率:5,151 msg/s
Classic 队列在发送和接收速率方面始终优于 Quorum 队列,在所有场景中都显示出更高的吞吐量。Quorum 队列虽然更具弹性,但吞吐量会下降,尤其是在接收速率方面。
2. 延迟
- 经典队列:
- 平均第 99 个百分位延迟:2308 万微秒。- 延迟保持可控并持续扩展,即使负载较高(2 个生产者,4 个消费者)也是如此。
- 仲裁队列:
- 平均第 99 个百分位延迟:3351 万 μs。- 延迟始终比传统队列高 40-50%,在较高负载下会出现显著峰值。
由于复制和容错能力,仲裁队列会引入更多的延迟。对于低延迟至关重要的应用程序,经典队列是队列的明确选择。
3. 可扩展性
- 经典队列:
- 随着负载的增加而线性扩展,在 1 个生产者/2 个消费者(场景 2)和 2 个生产者/4 个消费者(场景 3)的场景之间,发送和接收速率显着跳跃。
- 仲裁队列:
- 在高负载下吞吐量不佳。在具有 2 个生产者和 4 个使用者的方案 3 中,仲裁队列仅显示发送速率略有增加,接收速率略有下降,这表明与传统队列相比可扩展性较差。
Classic 队列可以有效地扩展,而 Quorum 队列则随着添加更多的创建者和使用者而显示吞吐量回报递减和延迟增加。
做出正确的选择
在 RabbitMQ 中,在 Classic Queues 和 Quorum Queues 之间进行选择取决于您的系统在性能、持久性、容错能力和资源可用性方面的特定要求。
何时选择 Classic Queues
- 高吞吐量和低延迟要求
- 非关键应用程序
- 单节点或低成本环境
何时选择 Quorum 队列
- 高可用性和容错能力
- 持久消息传递
- 分布式系统
- 任务关键型系统
Classic 队列和 Quorum 队列之间的权衡
方面 |
经典队列 |
仲裁队列 |
吞吐量 |
高吞吐量、低延迟 |
由于复制开销而降低吞吐量 |
耐久性 |
可选的单节点持久性 |
多节点复制的强大持久性 |
容错 |
有限(无复制,单节点故障影响) |
高容错性(多节点复制) |
可用性 |
取决于单节点可用性 |
通过自动领导者选举实现高可用性 |
资源使用情况 |
低(单节点,较少的磁盘和内存开销) |
高(多个节点,较高的 CPU、内存、磁盘使用率) |
延迟 |
低延迟(无复制) |
由于 Raft 复制导致更高的延迟 |
用例 |
高性能、非关键应用程序 |
关键应用程序、高可用性、无消息丢失 |
详细信息源
在决定 RabbitMQ 的 Classic 队列和 Quorum 队列时,重要的是要认识到两者各有优缺点。最佳选择取决于系统的特定需求。归根结底,在 Classic 队列和 Quorum 队列之间进行选择是一个决定,它取决于您在性能和可靠性之间的特定权衡:这是关于在速度和持久性之间找到适当的平衡。通过了解每种类型的队列的执行方式,您可以设计符合您的目标的 RabbitMQ 设置,无论是效率、健壮性,还是两者兼而有之。