深入了解消息队列:从基础到选型
目录
一、什么是消息队列
二、消息队列的优点
1、异步通信:
2、削峰填谷:
3、解耦:
4、可扩展性:
三、存在的问题
四、JMS与AMQP
JMS规范(Java 消息服务)
点对点模式
发布订阅模式
AMQP协议(高级消息队列协议)
五、常见的消息队列的对比
ActiveMQ
RabbitMQ
RocketMQ
Kafka
一、什么是消息队列
在分布式系统中,消息队列是一种重要的组件,它能实现不同服务之间的异步通信。就像一个可靠的邮差,当一个服务需要向另一个服务发送信息时,只需把信息放入消息队列,不用等待对方立即处理,对方可以在合适的时候从队列中取出并处理,这样大大提高了系统的灵活性和效率。
例如在电商平台中,用户下单后,订单系统需要通知库存系统减少库存、物流系统安排发货。此时,订单系统只需将下单信息发送到消息队列,库存系统和物流系统就可以各自从消息队列中获取信息并进行处理,而订单系统无需等待它们处理完成就能给用户返回下单成功的结果,极大地提升了用户体验。
简单来说,我们可以把消息队列看作是一个存放消息的容器,当我们需要使用消息的时候,直接从容器中取出消息供自己使用即可。
二、消息队列的优点
1、异步通信:
传统的同步通信中,发送方需要等待接收方处理完消息才能继续执行,而消息队列支持异步通信,发送方发送消息后可以立即返回,无需等待,提高了系统的响应速度和吞吐量。
2、削峰填谷:
在流量高峰期,大量的请求会涌向系统,如果直接处理可能会导致系统崩溃。消息队列可以暂时存储这些请求,让系统按照自身的处理能力逐步处理,避免了流量波动对系统的冲击。
3、解耦:
系统中的各个服务通过消息队列进行通信,无需直接相互调用,减少了服务之间的依赖关系。当一个服务需要修改时,只要保证消息的格式不变,其他相关服务无需做出调整,便于系统的维护和扩展。
4、可扩展性:
由于服务之间通过消息队列解耦,当系统需要扩展时,可以方便地增加新的服务节点来处理消息队列中的消息,提高系统的处理能力。
三、存在的问题
消息顺序性:在某些场景下,消息的处理顺序非常重要,例如电商平台中的订单支付、发货、收货等消息必须按照顺序处理。但消息队列在分布式环境下,可能会因为多个消费者同时处理消息,导致消息的顺序被打乱。
消息重复消费:由于网络波动、消费者故障等原因,可能会导致消息被重复发送或接收,从而出现消息重复消费的问题。如果处理不当,可能会导致数据错误,例如重复扣减库存等。
消息事务性:在一些业务场景中,需要保证消息的发送和业务操作的原子性,即要么业务操作成功且消息发送成功,要么两者都失败。这就需要消息队列支持事务性消息,但实现事务性消息比较复杂。
消息堆积与处理效率:当系统的消息产生速度超过消息处理速度时,会导致消息在队列中堆积。如果堆积的消息过多,可能会占用大量的存储空间,甚至影响消息队列的性能。同时,如何提高消息的处理效率也是一个需要解决的问题。
四、JMS与AMQP
JMS规范(Java 消息服务)
JMS 是 Java 平台上关于消息中间件的技术规范,它定义了一套标准的接口和消息格式,使得 Java 应用程序能够方便地与消息中间件进行交互。JMS 的消息模型主要有两种:点对点(P2P)模型和发布 / 订阅(Pub/Sub)模型。
点对点模型中,消息发送到一个队列中,只有一个消费者能够接收和处理该消息;发布 / 订阅模型中,消息发送到一个主题中,所有订阅了该主题的消费者都能接收到消息。JMS 主要适用于 Java 语言开发的应用程序,与 Java 生态系统集成良好。
点对点模式
点对点模式中,消息被发送到一个特定的队列中。消息队列会保存消息,直到有一个消费者从队列中取出并处理该消息。一旦消息被消费者接收并确认处理完成,消息队列就会将该消息从队列中删除,确保消息只会被一个消费者处理。
其特点如下:消息具有独占性,仅能被一个消费者处理。消费者无需在消息发送时处于运行状态,只要消息在队列中,当消费者启动后就能获取并处理消息。消息的生命周期与队列相关,若未被处理,会一直存在于队列中(除非设置了过期时间)。
适用场景:适用于任务分配、订单处理等需要唯一处理者的场景。例如,企业内部的任务调度系统,每个任务只能由一个工作人员处理,通过一对一模式将任务消息发送到队列,工作人员从队列中获取任务并处理。
发布订阅模式
发布订阅模式中,消息发布者将消息发送到一个主题(Topic)中,多个订阅者可以订阅该主题。当消息发送到主题后,所有订阅了该主题的订阅者都会收到该消息,实现消息的广播。
其特点如下:消息可以被多个订阅者接收和处理,实现一对多的通信。订阅者需要在消息发送前完成订阅,否则可能会错过之前发送的消息(除非主题支持消息持久化且订阅者设置了持久化订阅)。消息的生命周期与订阅者的订阅状态相关,若没有订阅者,消息可能会被直接丢弃(取决于消息队列的配置)。
适用场景:适用于需要向多个接收者广播信息的场景,如系统通知、实时数据更新、新闻推送等。例如,天气预警系统发布暴雨预警消息到主题,多个相关部门(交通、水利、应急等)订阅该主题,都能及时收到预警信息并采取相应措施。
AMQP协议(高级消息队列协议)
AMQP 是一种跨语言、跨平台的消息队列协议,它定义了消息的结构、交换器、队列等组件的规范,使得不同语言、不同平台的应用程序能够通过遵循 AMQP 协议的消息中间件进行通信。AMQP 的消息模型更加灵活,支持多种交换器类型,如直接交换器、主题交换器、扇形交换器等,可以根据不同的路由规则将消息路由到不同的队列中。
AMQP 具有更好的跨平台性和互操作性,适用于多语言开发的分布式系统。与 JMS 相比,AMQP 是一种协议,而 JMS 是一种规范,AMQP 的实现可以支持多种语言,而 JMS 的实现主要针对 Java 语言。
五、常见的消息队列的对比
activemq,babbitmq,rocketmq,kafka,
ActiveMQ
ActiveMQ 是一款比较成熟的开源消息队列,它支持 JMS 规范,能够很好地与 Java 应用集成。它提供了丰富的 API 和管理工具,功能较为全面,支持多种消息协议,如 OpenWire、STOMP、AMQP 等。在可靠性方面,ActiveMQ 支持消息持久化、事务、确认机制等,能够保证消息的可靠传递。不过,在高并发场景下,其性能可能会出现瓶颈,所以更适合中小规模的应用场景。
RabbitMQ
RabbitMQ 是基于 AMQP 协议实现的消息队列,具有良好的跨语言性和互操作性,支持多种编程语言。它的消息模型灵活,支持多种交换器类型,能实现复杂的路由规则。在可靠性上,RabbitMQ 支持消息持久化、确认机制、镜像队列等,可保障消息的可靠传输。其性能在中等并发场景下表现稳定,适用于对消息可靠性要求较高、需要灵活路由规则的场景,如金融、电商领域。
RocketMQ
RocketMQ 是由阿里巴巴开发的开源消息队列,后来捐献给了 Apache 基金会。它专为分布式系统设计,具有优异的性能,在高并发场景下表现出色,能够支持海量消息的存储和处理。RocketMQ 支持消息持久化、事务消息、重试机制等,可靠性高,并且与 Java 生态系统集成良好,支持集群部署、负载均衡等功能。它适用于大规模的分布式系统,尤其是电商、金融等对性能和可靠性要求较高的场景。
Kafka
Kafka 是一款高吞吐量的分布式消息队列,最初由 LinkedIn 开发,后捐献给 Apache 基金会。它主要用于日志收集、实时数据处理等场景,具有极高的吞吐量,能处理大量的实时数据。Kafka 通过副本机制保证消息的可靠性,不过在默认情况下可能存在一定的消息丢失风险。它支持消息的分区和复制,具有良好的扩展性,适合大数据场景,如日志采集、实时数据分析、流式处理等对吞吐量要求极高的场景。
对比方向 | 概要 |
---|---|
吞吐量 | 万级的 ActiveMQ 和 RabbitMQ 的吞吐量(ActiveMQ 的性能最差)要比 十万级甚至是百万级的 RocketMQ 和 Kafka 低一个数量级。 |
可用性 | 都可以实现高可用。ActiveMQ 和 RabbitMQ 都是基于主从架构实现高可用性。RocketMQ 基于分布式架构。 kafka 也是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用 |
时效性 | RabbitMQ 基于erlang开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。其他三个都是 ms 级。 |
功能支持 | 除了 Kafka,其他三个功能都较为完备。 Kafka 功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准 |
消息丢失 | ActiveMQ 和 RabbitMQ 丢失的可能性非常低, RocketMQ 和 Kafka 理论上不会丢失。 |
总结:
ActiveMQ 的社区算是比较成熟,但是较目前来说,ActiveMQ 的性能比较差,而且版本迭代很慢,不推荐使用。
RabbitMQ 在吞吐量方面虽然稍逊于 Kafka 和 RocketMQ ,但是由于它基于 erlang 开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。
RocketMQ 社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准 JMS 规范走的有些系统要迁移需要修改大量代码。
Kafka 的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms 级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展。kafka 唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响。