消息队列的应用场景
消息队列有很多的应用场景,比如流量削峰、数据分发、分布式事务等,之所以能支持这些应用场景,我个人认为是消息队列的两个核心特性在发挥作用:解耦和异步。
解耦
基于消息队列通信的情况下,生产者和消费者之间没有直接耦合。如果没有消息队列,每当一个新的业务方接入,我们都要联调新的接口。有了消息队列,生产者只需要关心消息是否成功发送到队列,至于如何消费消息是消费者自己的事情,这减少了开发和联调的工作量。
异步
在电子商务的一些秒杀促销活动中,使用消息队列可以提供流量削峰的作用。如果不使用消息队列,高并发的请求会让数据库压力剧增,使得响应速度变慢。如果将高并发产生的请求数据暂存在消息队列中,再由消费者进程从队列中获取数据并执行后续的业务逻辑,就可以有效抵御大量订单对系统的冲击。另外,假如系统需要进行故障修复或功能升级,数据也能暂存在消息队列中,等到系统恢复正常后,再从消息队列中获取数据并进行后续的处理。
消息队列带来的问题
系统可用性降低
系统引入的外部依赖越多,可用性就越低。
系统复杂度提高
消息没有被正确消费、消息重复消费、消息丢失、消息传递顺序错乱、 消息队列的高可用等这些以前没有的问题如今都需要解决。
消息模型
点对点

生产者将消息发送到队列中,消费者从队列中获取消息。
点对点模型的特点:
- 队列不能存储已经消费的消息,消费者不可能消息到已经被消费的消息
- 每个消息只有一个消费者和一个生产者
- 生产者发消息和消费者消费消息是异步解耦的
- 消费者接收到消息后,需要发送
ACK 确认。
发布/ 订阅

生产者将消息发布到话题中,所有订阅了话题的消费者都可以获取话题中的消息。
发布
- 每条消息都可以有多个消费者
- 消息者必须订阅
Topic 才可以消费生产者发布到Topic 中的消息 Topic 中的消息可被重复消费
推拉模型
消费者获取消息的方式分为两种,
实时性要求高的场景
采用
生产速率大于消费速率的场景
当生产速率大于消费速率时,有两种可能性:一种是生产者本身的效率就要比消费者高,例如消费者处理消息的业务逻辑可能很复杂,或者涉及到磁盘、网络等
消息队列产品比较
维度 | Kafka | RabbitMQ | ZeroMQ | RocketMQ | ActiveMQ |
---|---|---|---|---|---|
资料数量 | 资料数量中等,有文档也有书籍 | 资料数量多,有文档也有书籍 | 资料数量少 | 资料数量少,官方文档较简洁,有书籍 | 资料数量多,有文档也有书籍 |
开发语言 | Scala | Erlang | C | Java | Java |
协议 | 基于 | AMQP | TCP、UDP | 基于 | OpenWire、STOMP、REST、XMPP、AMQP |
消息存储 | 内存、磁盘、数据库,支持大量堆积 | 内存、磁盘,支持少量堆积 | 消息发送端的内存或者磁盘中,不支持持久化 | 磁盘,支持大量堆积 | 内存、磁盘、数据库,支持少量堆积 |
消息事务 | 支持 | 支持 | 不支持 | 支持 | 支持 |
负载均衡 | 支持 | 对负载均衡的支持较差 | 去中心化,不支持负载均衡,本身只是一个多线程网络库 | 支持 | 支持,可以基于 |
集群方式 | 无状态集群,每台服务器既是 | 支持简单集群模式,比如主备,对高级集群模式支持不好 | 去中心化,不支持集群 | 常用多对 | 支持简单集群模式,比如主备,对高级集群模式支持不好 |
管理界面 | 一般 | 良好 | 无 | 一般 | 一般 |
可用性 | 非常高(分布式) | 高(主从) | 高 | 非常高(分布式) | 高(主从) |
消息重复 | 支持 | 支持 | 差 | 支持 | 支持 |
吞吐量 | 极大 | 大 | 极大 | 很大 | 不大 |
订阅形式和消息分发 | 基于 | direct、topic、headers、fanout | 点对点 | 基于 | 点对点、发布 |
顺序消息 | 支持 | 不支持 | 不支持 | 支持 | 不支持 |
消息确认 | 支持 | 支持 | 支持 | 支持 | 支持 |
消息回溯 | 支持指定分区 | 不支持 | 不支持 | 支持指定时间点的回溯 | 不支持 |
消息重试 | 不支持,但是可以实现 | 不支持,但是可以利用消息确认机制实现 | 不支持 | 支持 | 不支持 |
并发度 | 并发度高 | 并发度极高 | 并发度高 | 并发度高 | 并发度高 |