吹雨听风

消息队列:RabbitMQ vs Kafka vs Redis vs NSQ vs Pulsar

标签: 技术 , 消息队列

在现代软件系统中,消息队列可谓是非常基础的软件,尤其在异步化的微服务架构中。消息队列可确保 用服务之间通信的可靠和稳定,同时使消息在系统全局内部得到监控和治理。

市面有许多消息队列产品,如成熟的 RabbitMQ,还有后期之秀如 Pulsar 和 NSQ。这些产品的功、特点、支持的数据规模各有不同,本文将对一些主流的消息产品进行基本的对比。

消息队列使用场景

消息队列的应用非常广泛,如在分布式系统中承担着消息通信的任务,提供异步化、可靠的消息传递服务; 在物联网系统中承担消息下发与数据汇集的工作, 是物联网平台中不可或缺的组成部份等。

通信服务

在微服务系统或分布式系统中,服务与服务之间有两种比较常见的通信方式:同步通信与异步通信。

在同步通信中,服务的调用方在发请调用后,面要等待服务提供方的响应,常在 http / rest 或 rcp 协议上运行。相反的,在异步的通信中,调用方将在消息发出后不必等待服务提供方的响应,此时通常面要使用消息队列产品来进行消息的治理。

异步通信相比于同步通信有许多的优点。

首先,异步通信是非阻塞的。调用方和服务方并不会直接的交互,调用方在消息发送成功后通信就完成了,不会等待其他服务对消息的处理结果,因此可以优化数据链路和数据流。

其次,提供更好的灵活性和扩展性。消息队例的引入,降低了系统组件之间的耦合,组件和组件之间的灵活性将大大提升,同样,由于组件之间不再直接进行通信,扩展性与伸缩性也会更好。

第三,提高更好的可用性。服务的调用方和服务提供方双方之间不直接联系,而是调用方将请求都发送给消息队列。利用消息队列对原本相互依赖的组件和系统时行分离,可以极大的提升容错的能力,即使在服务提供方故障时,调用方依然可以继续和队列进行交互,从而保证或局部保证了系统的可用性。

消息服务

在即时通讯 (IM) 系统中,消息队列了常被用于以下场景:

  1. 异步处理消息:IM 系统的消息处理需要耗时,例如图像转换,语音识别,文本分析等。消息队列可以用来缓存这些任务,使它们在后台独立的线程中处理,避免阻塞用户请求,提高系统效率。
  2. 解耦消息处理组件:IM 系统中的多个组件之间通信通常需要耗时,消息队列可以被用来解耦这些组件,避免相互影响,提高系统的稳定性。
  3. 消息持久化:消息队列可以存储消息,即使在系统宕机或其他异常情况下,消息也不会丢失。这对于 IM 系统中的消息通知等重要信息是非常有价值的。

消息队列为 IM 系统提供了一个高效的消息管理机制,帮助 IM 系统提高效率,提高稳定性,保证消息的可靠性。

物联网

消息列队同样在物联网系统中被用来解决各种问题:

  1. 解耦系统组件:物联网系统通常包括大量的组件,例如传感器,设备,云端服务器等。消息队列可以被用来解耦这些组件,避免相互依赖导致的系统停滞。
  2. 实现异步消息处理:物联网系统中的消息处理通常需要耗时,消息队列可以用来缓存这些任务,使它们在后台独立的线程中处理,避免阻塞其他任务,提高系统效率。
  3. 保证数据一致性:在物联网系统中,数据的传输通常需要处理大量的数据,消息队列可以用来缓存数据,确保数据的一致性,防止数据丢失或出错。
  4. 支持流量削峰:物联网系统中的数据流量可能在短时间内暴增,消息队列可以用来缓存数据,避免系统因数据流量过大而崩溃。

总的来说,消息队列在现在系统中有着不可或缺的地位,常用于实现异步通讯、应用解藕、削峰平谷等功能。

消息对列常见协议

JMS

Java Message Service的缩写,即Java消息服务。当然,JMS是与语言无关的协议标准,只要遵循该协议2个组件即可时行消息通信。

STOMP

流文本定向消息协议(Streaming Text Orientated Messaging Protocal),简单(流)文本定向消息协议,它提供了一个可互操作的连接格式,允许STOMP客户端与任意STOMP消息代理(Broker)进行交互。STOMP协议由于设计简单,易于开发客户端,因此在多种语言和多种平台上得到广泛地应用。

代表产品为:ActiveMQ、Apollo

AMQP

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

一个提供统一消息服务的应用层标准高级消息队列协议,与 HTTP 一样,AMQP 也是应用层协议的一个开放标准,为面向消息的中间件设计。

基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件不同产品,不同的开发语言等条件的限制。

RabbitMQ 是 AMQP 消息队列最有名的开源实现。

MQTT

消息队列遥测传输(Message Queuing Telemetry Transport)。由IBM开发,现在被广泛用于物联网场景。因为他的特点就是轻量,简单,开放和易于实现。所以它常用于很多计算能力有限、带宽低、网络不可靠的远程通信应用场景。

产品简单对比

Redis

我们常把Redis作为内存数据库来用,内存数据存储是它的核心功能,当然也用作高性的消息代理。不过 Redis 与其他消息代理有点不同。

需要特别注意的是,Redis 没有持久性,而是将其内存转储到磁盘/数据库中。它也非常适合实时数据处理。

自从 Redis 5.0 引入了 pub-sub 功能之后,消息对队得到了提升,也能很好的支付一对多的订阅场景。

RabbitMQ

RabbitMQ 于 2007 年发布,是最早创建的通用消息代理之一,它是开源的 AMQP 协议的代表。现如今支持 RabbitMQ 还支持 XMPP、SMTP、STOMP 等众多的其他消息协议,同时 RabbitMQ 还支持复杂的路由逻辑,或许这正是它持续火爆的原因。

在客户端方面,RabbitMQ 支持所有主流编程语言,包括 Python、Java、.NET、PHP、Ruby、JavaScript、Go、Swift 等。

Kafka

Kafka 由 Linkedin 于 2011 年创建,是一个分布式、分区的、多副本的、多生产者、多订阅者,基于 zookeeper 协调的分布式消息系统。Kafka 优势是支持高吞吐量、低延迟、并且支持持久化存储。同时也拥有众多语言的客户端实现。

NSQ

NSQ 是 Go 语言编写的一个开源的实时分布式内存消息队列,其性能十分优异。是近年比较流行的消息队列产品。NSQ提倡分布式和分散的拓扑结构,没有单点故障,支持容错和高可用性,并提供可靠的消息交付保证,同时支持横向扩展,没有任何集中式代理,并且部署也非常的简单。

Pulsar

Pulsar是一个高性能,分布式消息系统,它具有高吞吐量,低延迟,高可用性,支持多租户和多语言的特点。Pulsar还提供了一些附加功能,如存储分区,数据持久性,数据备份等。最初由 Yahoo 开发,目前由 Apache 软件基金会管理。

选择合适的消息队列产品

前面介绍了几个主流消息对队产品的特性。其中如 Redis / RabbitMQ / Kafaka 等产品目前处于如日中天的发展阶段,也能被各大云厂商原生支持,但正如前面所描述的,它们在实现方式上却有着天壤之别,这里对于消息队列产品的选择给出一些通用性的建议:

简单应用、短消息、临时: Redis

Redis 的内存数据库几乎非常适合不需要持久性的短消息用例。因为它提供了极快的服务和内存中功能,Redis 是持久性不是那么重要并且您可以容忍一些丢失的短期保留消息的理想选择。

Redis 5.0 之后的版本中,增强了 Pub / Sub 能力(Stream),如果有简单的一对多场景也可以作为备选。

汇集海量数据与处理:Kafaka

Kafka是一个高吞吐量、可靠性、分布式、灵活性和易于扩展的消息系统,专为长时间存储大量数据而构建。主要应用于数据流管理、日志处理、应用间通信和消息队列等场景。

消息路由复杂:RabbitMQ

RabbitMQ 作为老牌的、成熟的消息代理,高可用性、易于扩展、强大的路由功能和多种协议支持的特点,周时能够很好的支持复杂路由配置。主要应用于分布式系统的异步通信、应用间消息传递和任务队列等场景。

需要利用延时特性: RabbitMQ / NSQ / Pulsar / ActiveMQ

延迟队列可让新消息传递操作推迟特定的时常,在等待期间消费者不可见。在实际的使用中常基于此特性实现延迟的重复推送以保证投递的可靠性。如果您的应用有此需求可以考虑这几款支持延时特性的产品。

需要简化部署:NSQ / Redis

Redis 作为最基础的产品,已被特大云厂商普遍支持,即使需要私有部署也非常的容易。

而 NSQ 作为一款近几年兴起的,使用 Go 语言编写的一个开源产品,除了支持良好的性能,还非常的易于配置和部署,并且内置了管理界面。

消息队列产品技术词汇

同样,在最后整理了与消息队列上关的技术名词和概念,如有需要可自行进一步深入了解。注意:这里的名词混合了各产品的名词,特定的产品可能只包含下面部份名词也指代的角色。

  • Broker:代理,消息队列系统的核心部分,负责维护队列并转发、管理消息,通种表示消息队列服务的实体。
  • Message:消息,消息队列中存储的单元数据。
  • Producer / Publisher:生产者,负责生成并发送消息到消息队列。
  • Consumer / Subscriber:消费者,负责从消息队列中接收并处理消息。
  • Queue:队列,消息存储的容器,消息队列系统可以管理多个队列。
  • ACK:确认,消费者在处理完消息后向代理发送确认,代表该消息已经被成功处理。
  • Channel:信道,指消息代理中的虚拟连接。它在应用程序和消息代理之间提供了一条用于发送和接收消息的通信路径。
  • Topic:主题,消息的类别,生产者向某个主题发送消息,消费者从某个主题接收消息。
  • Durable:持久性,消息队列支持持久性消息,即消息不会因系统故障丢失。
  • Load Balancing:负载均衡,消息队列系统支持负载均衡,可以将消息均衡地分配给多个消费者。
  • Routing:路由,负责将消息队列中的消息分发与路由。根据消息的特征,选择相应的路由规则,将消息分发/分配给对应的消费者。
  • Pub/Sub:发布/订阅,消息队列支持发布/订阅模型,生产者向主题发布消息,
  • Delay Message:延时消息,消息队列中存储的消息在一定的时间后才能被消费者消费。
  • Dead Message:死信,超时未消费的消息或是超过最大重试次数后,依然无法消费的消息。
  • Dead-Letter-Queue:死信对列,用于处理无法被正常消费的消息队列。
  • Exchange:RabbitMQ 的路由代理。将消息路由到一个或多个Queue。Exchange 通常根据 Binding Key、Routing Key 以及 Headers 属性路由消息。
  • PlayLoad:负载,等同说消息。

扩展阅读: