深入了解消息队列

Posted by icoding168 on 2020-04-07 22:40:48

分类:

消息队列的应用场景

消息队列有很多的应用场景,比如流量削峰、数据分发、分布式事务等,之所以能支持这些应用场景,我个人认为是消息队列的两个核心特性在发挥作用:解耦和异步。

解耦

基于消息队列通信的情况下,生产者和消费者之间没有直接耦合。如果没有消息队列,每当一个新的业务方接入,我们都要联调新的接口。有了消息队列,生产者只需要关心消息是否成功发送到队列,至于如何消费消息是消费者自己的事情,这减少了开发和联调的工作量。 从面向对象编程的角度来说,消息队列相当于一个高度抽象的接口,通过实现这个接口,生产者和消费者都可以独立地修改现有的功能或加入新的扩展。

异步

在电子商务的一些秒杀促销活动中,使用消息队列可以提供流量削峰的作用。如果不使用消息队列,高并发的请求会让数据库压力剧增,使得响应速度变慢。如果将高并发产生的请求数据暂存在消息队列中,再由消费者进程从队列中获取数据并执行后续的业务逻辑,就可以有效抵御大量订单对系统的冲击。另外,假如系统需要进行故障修复或功能升级,数据也能暂存在消息队列中,等到系统恢复正常后,再从消息队列中获取数据并进行后续的处理。

消息队列带来的问题

系统可用性降低

系统引入的外部依赖越多,可用性就越低。

系统复杂度提高

消息没有被正确消费、消息重复消费、消息丢失、消息传递顺序错乱、 消息队列的高可用等这些以前没有的问题如今都需要解决。

消息模型

JMS 规范定义的消息模型有两种:点对点(Point To Point)和发布/订阅(Publish/Subscribe)。

点对点

生产者将消息发送到队列中,消费者从队列中获取消息。

点对点模型的特点:

  • 队列不能存储已经消费的消息,消费者不可能消息到已经被消费的消息
  • 每个消息只有一个消费者和一个生产者
  • 生产者发消息和消费者消费消息是异步解耦的
  • 消费者接收到消息后,需要发送 ACK 确认。

发布/订阅

生产者将消息发布到话题中,所有订阅了话题的消费者都可以获取话题中的消息。

发布/订阅模型的特点:

  • 每条消息都可以有多个消费者
  • 消息者必须订阅 Topic 才可以消费生产者发布到 Topic 中的消息
  • Topic 中的消息可被重复消费

推拉模型

消费者获取消息的方式分为两种,Push 和 Pull,也就是推送和拉取。Push 模型是指一旦有新的消息产生,消息队列就推送消息给消费者,而 Pull 模型是由消费者定时去队列拉取消息。两种模型在不同的应用场景中各有优势:

实时性要求高的场景

采用 Push 模型的情况下,一旦消息到达,服务端即可马上将其推送给消费者,这种方式的实时性非常好;而采用 Pull 模型的情况下,为了不给服务端造成压力,消费者需要控制好轮询的间隔时间,而且当数据量不足时,不停的轮询显得毫无意义,这必然会给实时性带来一定的影响。

生产速率大于消费速率的场景

当生产速率大于消费速率时,有两种可能性:一种是生产者本身的效率就要比消费者高,例如消费者处理消息的业务逻辑可能很复杂,或者涉及到磁盘、网络等 I/O 操作;另一种是消费者出现故障,导致短时间内无法消费或消费不畅。Push 模型由于无法得知当前消费者的状态,只要有数据产生,便会不断地进行推送。在以上两种情况下,可能会导致消费者的负载进一步加重,甚至崩溃,除非消费者有合适的反馈机制能够让服务端知道自己的状况。而采取 Pull 模型问题就简单了许多,由于消费者是主动到服务端拉取数据,此时只需要降低访问频率即可。

消息队列产品比较

维度KafkaRabbitMQZeroMQRocketMQActiveMQ
资料数量资料数量中等,有文档也有书籍资料数量多,有文档也有书籍资料数量少资料数量少,官方文档较简洁,有书籍资料数量多,有文档也有书籍
开发语言ScalaErlangCJavaJava
协议基于 TCP 的自定义协议AMQPTCP、UDP基于 TCP 的自定义协议OpenWire、STOMP、REST、XMPP、AMQP
消息存储内存、磁盘、数据库,支持大量堆积内存、磁盘,支持少量堆积消息发送端的内存或者磁盘中,不支持持久化磁盘,支持大量堆积内存、磁盘、数据库,支持少量堆积
消息事务支持支持不支持支持支持
负载均衡支持对负载均衡的支持较差去中心化,不支持负载均衡,本身只是一个多线程网络库支持支持,可以基于zookeeper实现负载均衡
集群方式无状态集群,每台服务器既是 Master 也是 Slave支持简单集群模式,比如主备,对高级集群模式支持不好去中心化,不支持集群常用多对 Master-Slave 模式支持简单集群模式,比如主备,对高级集群模式支持不好
管理界面一般良好一般一般
可用性非常高(分布式)高(主从)非常高(分布式)高(主从)
消息重复支持at least once、at most once支持at least once、at most once支持at least once支持at least once
吞吐量极大极大很大不大
订阅形式和消息分发基于topic以及按照topic进行正则匹配的发布订阅模式direct、topic、headers、fanout点对点基于topic/messageTag以及按照消息类型、属性进行正则匹配的发布订阅模式。点对点、发布-订阅
顺序消息支持不支持不支持支持不支持
消息确认支持支持支持支持支持
消息回溯支持指定分区offset位置的回溯不支持不支持支持指定时间点的回溯不支持
消息重试不支持,但是可以实现不支持,但是可以利用消息确认机制实现不支持支持不支持
并发度并发度高并发度极高并发度高并发度高并发度高