转载自:The System Design Cheat Sheet: Message Queues - ActiveMQ, RabbitMQ, Kafka, ZeroMQ
本文由 Aleksandr Gavrilenko 发布于2023年12月21日
1. 前言
消息队列是异步服务到服务通信的一种形式。它们对于增强系统的可扩展性、可靠性和可维护性非常重要。
主要功能包括:
- 异步通信:允许系统的不同部分进行通信,而无需立即响应,从而更有效地使用资源。
- 服务解耦:使服务能够独立运行,降低系统的复杂度,增强可维护性和可扩展性。
- 负载均衡:将消息均匀分布在不同的服务或工作线程之间,有助于管理工作负载并提高系统性能。
- 有序保留:某些消息队列可以确保消息按照发送顺序进行处理,这对于特定应用程序至关重要。
- 可扩展性:通过添加更多使用者或资源来处理增加的消息流,从而促进应用程序的轻松扩展。
- 速率限制:控制消息处理的速率,这对于管理资源和防止系统过载非常重要。
- 扇出功能:消息队列通常包含扇出机制,该机制允许将单个消息同时传递给多个使用者或服务。
- 数据持久性:提供将消息存储在磁盘或内存中的能力,直到它们被成功处理,确保在系统故障的情况下数据不会丢失。
- **消息过滤和路由:**允许根据特定条件或内容路由或过滤消息,从而实现更有针对性和更高效的处理。
2. 组件
对于消息队列的内容,核心的概念是生产者(Producer) 、消费者(Consumer)和消息(Message)。
- 生产者(Producer) 是一个应用程序或服务,负责创建消息并将其发送到消息队列。它不需要知道谁将处理消息或何时处理消息。
- **消费者(Consumer)**是从队列中检索和处理消息的应用程序或服务。它作用于生产者发送的数据。
- **消息(Message)**是从生产者发送到消费者的数据包。它们的大小和格式可能有所不同,范围从简单的文本字符串到复杂的数据结构(如 JSON 或 XML)。
- 消息代理(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的模式可能需要一个陡峭的学习曲线。
- 缺乏中央代理:虽然这可能是一个优势,但它也意味着需要对消息传递系统进行更集中的管理、监控和控制。