【转载翻译】消息队列 - ActiveMQ、RabbitMQ、Kafka、ZeroMQ

转载自本人博客:【转载翻译】消息队列 - ActiveMQ、RabbitMQ、Kafka、ZeroMQ

转载自:The System Design Cheat Sheet: Message Queues - ActiveMQ, RabbitMQ, Kafka, ZeroMQ

本文由 Aleksandr Gavrilenko 发布于2023年12月21日

1. 前言

消息队列是异步服务到服务通信的一种形式。它们对于增强系统的可扩展性、可靠性和可维护性非常重要。

主要功能包括:

  1. 异步通信:允许系统的不同部分进行通信,而无需立即响应,从而更有效地使用资源。
  2. 服务解耦:使服务能够独立运行,降低系统的复杂度,增强可维护性和可扩展性。
  3. 负载均衡:将消息均匀分布在不同的服务或工作线程之间,有助于管理工作负载并提高系统性能。
  4. 有序保留:某些消息队列可以确保消息按照发送顺序进行处理,这对于特定应用程序至关重要。
  5. 可扩展性:通过添加更多使用者或资源来处理增加的消息流,从而促进应用程序的轻松扩展。
  6. 速率限制:控制消息处理的速率,这对于管理资源和防止系统过载非常重要。
  7. 扇出功能:消息队列通常包含扇出机制,该机制允许将单个消息同时传递给多个使用者或服务。
  8. 数据持久性:提供将消息存储在磁盘或内存中的能力,直到它们被成功处理,确保在系统故障的情况下数据不会丢失。
  9. **消息过滤和路由:**允许根据特定条件或内容路由或过滤消息,从而实现更有针对性和更高效的处理。

2. 组件

对于消息队列的内容,核心的概念是生产者(Producer)消费者(Consumer)消息(Message)

  1. 生产者(Producer) 是一个应用程序或服务,负责创建消息并将其发送到消息队列。它不需要知道谁将处理消息或何时处理消息。
  2. **消费者(Consumer)**是从队列中检索和处理消息的应用程序或服务。它作用于生产者发送的数据。
  3. **消息(Message)**是从生产者发送到消费者的数据包。它们的大小和格式可能有所不同,范围从简单的文本字符串到复杂的数据结构(如 JSON 或 XML)。
  4. 消息代理(Message Broker) 是一个中间件工具,它通过接收来自发送方的消息并将其路由到适当的接收方,从而促进不同应用程序或服务之间的通信。它通常提供消息队列、路由、转换和传递保证等功能。

3. 消息传递模型

3.1 两种通用消息传递模型

总的来说,有两种类型的消息传递:点对点消息传递和发布-订阅消息传递。

3.1.1 点对点(Point-to-Point)
  • 生产者发送的消息被放置在队列(Queue)中,并由单个使用者使用。
  • 它确保每条消息仅由一个接收者处理一次。
3.1.2 发布-订阅(Publish-Subscribe)
  • 消息将发布到特定主题(Topic),而不是队列,不仅给单个使用者使用。
  • 多个消费者可以订阅一个主题,并接收广播到该主题的消息。

3.2 额外消息交换模式

但是,某些消息传递协议和支持它们的代理使用额外的交换(Exchange)组件进行路由。在这种情况下,消息将首先发布到代理中的交换模块。Exchange 充当路由代理,使用其路由规则将这些消息转发到相应的队列。

区分了以下交换模式:

3.2.1 直接交换(Direct exchange)
  • 消息被路由到其绑定键与消息的路由键匹配的队列。
3.2.2 话题交换(Topic exchange)
  • 主题交换将在路由键和绑定中指定的路由模式之间执行通配符匹配,以将消息发布到队列。
3.2.3 扇出交换(Fanout exchange)
  • 发送到扇出交换的消息将被复制并转发到绑定到该交换的所有队列。
3.2.4 标头交换(Header exchange)
  • 标头交换将使用消息标头属性进行路由。
3.2.5 死亡信件(Dead letter)
  • 死亡信件队列收集由于各种原因(如处理错误、消息过期或传递问题)而无法成功处理的消息。

4. 协议

消息代理负责将消息从生产者传递到使用者。它们使用特定的协议来定义消息传递的规则和格式。

此域中最受欢迎的协议为以下几种:

4.1 AMQP

全称 Advanced Message Queuing Protocol(高级消息队列协议)

一种二进制协议,专为面向消息的中间件而设计,具有鲁棒性、安全性和互操作性。适用于复杂而可靠的企业消息传递系统。

  • **使用案例:**企业应用程序、财务系统和业务流程
  • **消息模型:**点对点、发布-订阅
  • **安全性:**TLS/SSL、SASL、PLAIN
  • **寻址:**使用具有路由功能的基于交换和队列的寻址
  • **架构实现:**基于代理库

4.2 MQTT

全称 Message Queuing Telemetry Transport,消息队列遥测传输

一种轻量级的发布-订阅网络协议,针对高延迟或不可靠的网络进行了优化,非常适合 IoT 方案。

  • **使用案例:**物联网设备、家庭自动化、移动消息应用程序
  • **消息传递模型:**发布-订阅
  • **安全:**TLS/SSL、SASL、普通
  • **寻址:**它使用基于主题的寻址,其中消息将发布到主题
  • **架构实现:**基于代理库

4.3 JMS

全称 Java Message Service,Java 消息服务

基于 Java 的消息传递标准为 Java 应用程序中的点对点和发布-订阅消息传递模式提供了接口。

  • **使用案例:**企业 Java 应用程序,集成多个基于 Java 的系统
  • **消息模型:**点对点、发布-订阅
  • **安全:**依赖于底层 Java EE 安全模型
  • **寻址:**使用 JNDI 查找队列和主题
  • **架构实现:**它通常在企业服务总线或应用程序服务器之上实现。

4.4 STOMP

全称 Simple Text Oriented Messaging Protocol,面向简单文本的消息传递协议

一种简单的基于文本的协议,易于实现,适用于不需要优先考虑高级消息传递功能的方案。

  • **使用案例:**快速开发环境和简单的消息传递应用程序
  • **消息模型:**点对点、发布-订阅
  • **安全:**平原;依赖于底层传输协议进行加密
  • **寻址:**基于帧,带有目标、内容类型等的标题。
  • **架构实现:**基于代理库

4.5 Kafka

全称 Kafka Protocol,Kafka协议

与 Apache Kafka 相关联,Apache Kafka 是一个能够处理高吞吐量数据流的分布式流式处理平台。

  • **使用案例:**实时分析、数据管道、流处理应用程序
  • **消息传递模型:**发布-订阅
  • **安全:**SSL/TLS、SASL
  • **寻址:**基于主题,具有可伸缩性分区功能。
  • **架构实现:**具有代理和协调的分布式系统架构。

4.6 ZMTP

全称 ZeroMQ Message Transport Protocol,ZeroMQ 消息传输协议

ZeroMQ 的底层协议是一个高性能异步消息传递库,用于构建可扩展的分布式应用程序。

  • **使用案例:**高吞吐量、低延迟应用程序、微服务架构。
  • **消息模型:**请求-回复、发布-订阅、流水线、独占对等。
  • **安全:**PLAIN、CurveZMQ 和 ZAP
  • **寻址:**使用套接字灵活寻址
  • **架构实现:**基于库,支持无代理设计或各种代理配置

5. 代理库

ActiveMQ RabbitMQ Kafka ZeroMQ
编写语言 JAVA Erlang Scala C++
跨平台 是的 是的 是的 是的
开源 是的 是的 是的 是的
多种语言 是的 是的 是的 是的
支持协议 AMQP、AUTO、MQTT、OpenWire、REST、RSS 和 Atom、Stomp、WSIF、WS 通知、XMPP、WebSocket AMQP、STOMP、MQTT、HTTP 基于 TCP 的二进制文件 TCP、UDP、inproc、PGM、IPC、TIPC、NORM、SOCKS5
服务质量 至少一次 最多一次 至少一次 最多一次 至少一次,最多一次,恰好一次一次 至少一次 最多一次
消息模式 队列、Pub-Sub 队列、Pub-Sub、RPC 发布-订阅 Request-Reply、Pub-Sub、Push-Pull、Dealer and Router、Pair、Exclusive Pair等
持性久 磁盘、数据库 内存、磁盘 磁盘 -

5.1 ActiveMQ

Apache ActiveMQ 是由 Apache 设计的开源、多协议、基于 Java 的消息代理。它以其稳健性和灵活性而闻名,支持各种消息传递协议和客户端,使其成为集成不同系统的多功能选择。

架构特点:

  • 多协议支持:ActiveMQ支持多种消息传递协议,包括AMQP、MQTT、OpenWire、STOMP、JMS等,对不同客户端需求的适应性强。
  • JMS Provider:作为 JMS Provider,ActiveMQ 遵循 JMS API,该 API 允许 Java 应用程序的松耦合、异步通信和可靠性。
  • 基于代理的架构:ActiveMQ 使用代理架构,其中中央代理处理消息路由、传递和队列。
  • 可插拔持久化和存储:提供消息持久化选项,包括数据库存储(持久化)和文件系统存储,支持高性能和高持久化场景。
  • 集群和负载均衡:支持集群和负载均衡,实现高可用性和可扩展性。
  • 客户端确认:提供不同的消息确认选项,增强消息可靠性。

使用场景:

  • 企业集成:非常适合在企业内集成不同的系统,主要是在使用基于 Java 或多个协议的情况下。
  • 异步通信:在必须解耦系统组件的情况下很有用,例如在微服务体系结构中。
  • 分布式计算(Distributed Computing):促进分布式系统中的消息通信,保证数据的一致性和可靠性。
  • 物联网通信:可用于物联网设置,尤其是在首选 MQTT 的情况下。

优点:

  • 协议支持的多功能性:ActiveMQ 的主要优势之一是它支持多种协议,在各种环境中提供灵活性。
  • 可靠性和耐久性:提供可靠的消息传递和持久的存储。
  • 集群和高可用性:支持集群以实现负载均衡和高可用性。
  • **JMS 支持:**对 JMS API 的全面支持使其成为基于 Java 的系统的有力候选者。

缺点:

  • 性能:虽然 ActiveMQ 很强大,但可能无法与一些较新的消息代理的性能匹配,尤其是在吞吐量要求极高的场景中。
  • 复杂配置:可能难以配置和管理,尤其是在集群设置中。
  • 资源使用:可能需要大量资源,尤其是在重负载下,以获得最佳性能。
  • 管理和监控: 虽然它提供了管理工具,但它们可能不如一些较新的经纪人全面和用户友好。

5.2 RabbitMQ

RabbitMQ 是一个开源的消息代理软件,被称为面向消息的中间件。它是用 Erlang 编写的,基于 Open Telecom Platform 框架构建,用于集群和故障转移。RabbitMQ 广泛用于处理异步处理,通过各种消息传递协议(主要是 AMQP(高级消息队列协议))实现分布式系统之间的通信。

架构特点:

  • 支持多种消息传递协议:虽然 RabbitMQ 主要以 AMQP 而闻名,但它也通过插件支持 MQTT、STOMP 和其他协议。
  • 生产者-消费者模型:它遵循标准的生产者-消费者模式,其中生产者发送消息,消费者接收消息,RabbitMQ 充当代理。
  • Exchange-Queue 绑定:RabbitMQ 中的消息被发布到交换,然后根据路由键和模式路由到绑定队列。
  • 持久消息传递和瞬态消息传递:支持持久消息(在磁盘上持久保存)和瞬态消息(内存中)消息。
  • 集群和高可用性:RabbitMQ 可以集群以实现高可用性和可扩展性,在多个节点之间分配队列。
  • **灵活的路由:**为不同的路由逻辑提供多种交换类型(如直接、主题、扇出和标头)。
  • 可插拔认证和授权:支持可插拔认证模块,包括 LDAP。

使用场景:

  • 异步处理:非常适合解耦 Web 应用程序中的繁重处理任务,确保响应式用户界面。
  • 服务间通信:在微服务架构中用于服务之间的通信。
  • 任务队列:非常适合处理后台任务,如发送电子邮件或处理图像。
  • 分布式系统:促进分布式系统中的消息通信,保持一致性和可靠性。

优点:

  • 可靠性:RabbitMQ 以其可靠性和确保消息传递的能力而闻名。
  • 灵活的路由能力:其路由能力比许多消息代理的路由能力更先进。
  • 可扩展性和高可用性:支持可扩展的集群,这对于大规模应用程序至关重要。
  • 广泛的协议支持:支持多种消息传递协议的能力提高了适应性。
  • 管理界面:带有用户友好的管理界面,可简化监视和管理消息流。

缺点:

  • 学习曲线:对于初学者来说,了解 RabbitMQ 的路由和设置可能很复杂。
  • 内存使用:它可能占用大量内存,尤其是在重负载下,需要适当的监控和调整。
  • Erlang 依赖性:基于 Erlang 构建,它引入了一个额外的技术堆栈,团队可能需要熟悉这些技术堆栈。
  • 高负载下的性能:虽然通常性能较高,但在极高负载或复杂的路由方案中,可能需要进行性能调整。

5.3 Kafka

Apache Kafka是由 LinkedIn 开发的开源流处理软件平台,后来捐赠给了 Apache 软件基金会。它旨在处理大量数据并实现实时数据处理。Kafka 是一种分布式、分区和复制的提交日志服务。

架构特点:

  • 生产者-消费者模型:Kafka 以生产者-消费者模型运行。生产者向 Kafka 主题发布消息,消费者订阅这些主题以阅读消息。
  • 主题和分区:Kafka 中的数据分为多个主题。每个主题都可以拆分为多个分区,从而允许并行数据处理。分区还使 Kafka 能够水平扩展。
  • 分布式系统:Kafka 在一台或多台服务器上作为集群运行,Kafka 集群将记录流存储在称为主题的类别中。
  • 复制:Kafka 跨多个节点(代理)复制数据,以确保容错性。如果一个节点发生故障,可以从其他节点检索数据。
  • Zookeeper 协调:Kafka 使用 ZooKeeper 进行集群管理和协调,保证集群间的一致性。
  • 提交日志存储:Kafka 将所有数据存储为一系列记录(或提交日志),提供持久的消息存储。

使用场景:

  • 实时数据处理:非常适合实时分析和监控系统,在这些系统中,快速数据处理至关重要。
  • 事件溯源:适用于记录应用程序中的事件序列。
  • 日志聚合:有效用于收集和处理来自多个服务的日志。
  • 流处理:可用于复杂的流处理任务,如聚合数据流或实时过滤。
  • 与大数据技术集成:通常与大数据工具一起使用,进行数据处理和分析。

优点:

  • 高吞吐量:可以处理大量数据和许多并发事务。
  • 可扩展性:易于水平和垂直扩展。
  • 持久性和可靠性:提供持久的消息存储。
  • 容错性:由于数据复制,容错性高。
  • 灵活性:可用于广泛的用例,从消息传递系统到活动跟踪和日志聚合。

缺点:

  • 复杂性:设置和管理可能很复杂,尤其是对于大型集群。
  • 资源密集型:可能是资源密集型的,需要大量的内存和 CPU。
  • **对 ZooKeeper 的依赖性:**依赖 ZooKeeper 进行协调,添加额外的组件进行管理。
  • 延迟:虽然速度很快,但可能不适合需要极低延迟的用例。

5.4 ZeroMQ

ZeroMQ(ØMQ、0MQ 或 ZMQ)是用于分布式或并发应用程序的高性能异步消息库。它不是一个消息代理,而是一个库,它将套接字通信抽象为面向消息的中间件,从而更容易以可扩展的方式实现复杂的通信模式。ZeroMQ是用C++开发的,可以通过绑定在各种编程语言中使用。

架构特点:

  • 基于套接字的通信:ZeroMQ 使用套接字来抽象出低级网络编程的复杂性。这些套接字可用于发布-订阅、请求-回复和扇出等模式。
  • 无代理设计:与传统的消息代理不同,ZeroMQ 是无代理的,允许端点之间直接通信,而无需中央消息代理。
  • **可扩展的多线程:**提供了一种通过基于套接字的通信管理多个线程的方法,从而促进了可扩展的 I/O 绑定操作。
  • 异步 I/O:支持非阻塞、异步 I/O 操作,这对于构建响应迅速的高性能应用程序至关重要。
  • **与语言无关:**为多种编程语言提供绑定,使其可以从不同的技术堆栈进行访问。

使用场景:

  • 微服务:非常适合微服务架构中的服务间通信。
  • 高性能计算:用于性能至关重要的并行处理系统。
  • 分布式系统:适合需要复杂的分布式消息传递模式的场景,而不需要代理的开销。
  • 实时通信:在需要低延迟、实时数据交换的系统中有效。

优点:

  • 高性能:ZeroMQ专为高吞吐量和低延迟而设计,适用于性能关键型应用。
  • 消息传递模式的灵活性:支持多种消息传递模式,为不同的通信场景提供灵活性。
  • 降低复杂性:无代理架构简化了部署,降低了系统复杂性。
  • 可扩展性:通过对多个连接的有效处理,方便了应用程序的扩展。
  • 轻量级:与传统消息传递代理相比,资源密集程度更低。

缺点:

  • 没有内置持久性或消息持久性:缺乏内置的消息持久性或持久性支持,必须在外部处理。
  • 需要显式管理连接:开发人员需要管理连接,重试和错误处理,这可能会增加应用程序逻辑的复杂性。
  • 学习曲线:理解和有效使用ZeroMQ的模式可能需要一个陡峭的学习曲线。
  • 缺乏中央代理:虽然这可能是一个优势,但它也意味着需要对消息传递系统进行更集中的管理、监控和控制。
相关推荐
人才程序员6 分钟前
QML z轴(z-order)前后层级
c语言·前端·c++·qt·软件工程·用户界面·界面
bug_null7 分钟前
RabbitMQ消息可靠性保证机制7--可靠性分析-rabbitmq_tracing插件
分布式·rabbitmq
kingbal8 分钟前
RabbitMQ:添加virtualHost
分布式·rabbitmq
w(゚Д゚)w吓洗宝宝了9 分钟前
C vs C++: 一场编程语言的演变与对比
c语言·开发语言·c++
小老鼠不吃猫2 小时前
C++点云大文件读取
开发语言·c++
姚先生972 小时前
LeetCode 35. 搜索插入位置 (C++实现)
c++·算法·leetcode
BUTCHER52 小时前
Kafka安装篇
分布式·kafka
CoderCodingNo3 小时前
【GESP】C++二级考试大纲知识点梳理, (4)流程图
开发语言·c++·流程图
小小unicorn3 小时前
【C++初阶】STL详解(十三)—— 用一个哈希表同时封装出unordered_map和unordered_set
java·c++·散列表
慕羽★3 小时前
详细介绍如何使用rapidjson读取json文件
linux·c++·windows·json·file·param·rapidjson