消息队列科普文

489 阅读6分钟

「本文已参与好文召集令活动,点击查看:后端、大前端双赛道投稿,2万元奖池等你挑战!

消息队列

什么是消息队列

消息队列,或者称为大家常说的消息中间件,顾名思义,首先它是一种队列。平时像 Java 中常见的队列,作为一种存储数据的容器,具备先进先出的特性。

而类比一下,我们也可以理解为消息队列也就是一种存储消息的容器;不过相比较于一种语言中所定义的容器,它本身支持更底层的协议或者标准,提供应用与应用之间消息可靠传递的能力。

消息队列作为分布式系统中重要的组件,使用消息队列主要是为了通过异步处理提高系统性能和削峰、降低系统耦合性。

为什么要使用消息队列

消息队列凭借其独特的特性,在不同的应用场景下可以展现不同的作用。但总的来说,一般可以概况为以下几种作用:逻辑解耦、异步提高性能

1.逻辑解耦

68747470733a2f2f6d792d626c6f672d746f2d7573652e6f73732d636e2d6265696a696e672e616c6979756e63732e636f6d2f323031392d31312f2545362542362538382545362538312541462545392539382539462545352538382539372d2545382541372541332545382538302541362e706e67

从传统的生产者处理完逻辑,需要通知消费者执行。如果后面加入一个新的消费者,生产者就需要修改逻辑。

而引入消息队列以后,生产者只需要将通知消息发到消息队列,无论是多少个消费者,只要订阅消息队列就都能收到通知。并且消息队列提供了存储、可靠性传递、顺序消费等特性,如果需要生产者自己保证消息可靠传递,消费者自己保证顺序消费,那么其成本无疑是非常高的。

2.异步提高性能

异步通知的应用场景很多,比如消息缓冲、削峰等。

image-20200628214856018

如上图,传统模式下,客户端请求服务端,服务端处理完逻辑,并将数据落库之后,返回响应给客户端。

正常情况下,该流程是顺畅无比的。但是在高并发情况下,比如 B 站某个UP主突然打了个广告,应用流量激增10倍。原先数据库能力最大只能承载平时的五倍,现在的流量就会导致数据库压力过大,导致当前许多请求响应时间过长,甚至失败,并且可能影响其他流程。

image-20200628215750700

引入消息队列以后,即使流量激增10倍,应用也能快速响应,数据库的能力将不会成为影响主流程的瓶颈。

由于消息队列服务器处理速度快于数据库(消息队列也比数据库有更好的伸缩性),因此响应速度得到大幅改善。

而消费端可以慢慢地从消息队列中取出消息进行落库,而不用担心写入操作太多。

即使消费端消费速度太慢,可以很简单地扩展,只需要适量增加消费者的数量或处理消息的数量,就可以提高消息消费的速度。

因此,可以看出消息队列具有很好的削峰作用的功能——即通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。

11111

消息队列带来的问题

  • 系统可用性降低: 系统可用性在某种程度上降低,为什么这样说呢?在加入MQ之前,你不用考虑消息丢失或者说MQ挂掉等等的情况,但是,引入MQ之后你就需要去考虑了!
  • 系统复杂性提高: 加入MQ之后,你需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题!
  • 一致性问题: 我上面讲了消息队列可以实现异步,消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了!

消息队列选型

对比方向ActiveMQRabbitMQRocketMQKafka
吞吐量万级的 ActiveMQ 和 RabbitMQ 的吞吐量(ActiveMQ 的性能最差)要比 十万级甚至是百万级的 RocketMQ 和 Kafka 低一个数量级。万级十万级十万级
可用性基于主从架构实现高可用性基于主从架构实现高可用性分布式架构实现分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用
时效性ms 级RabbitMQ 基于erlang开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。ms 级ms 级
功能支持较为完备较为完备较为完备较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准
消息丢失可能性非常低可能性非常低理论上不会丢失理论上不会丢失
事务消息支持支持支持支持
协议支持
AMQPMQTTXMPPSTOMPJMS
ActiveMQYYNSupported By ActiveMQ-CPPY
RabbitMQYYNY(by pl)Y
RocketMQNNNNN
ActiveMQ ArtemisYYNYY
OpenFireNNYNN
Tigase XMPP ServerNNYNY
NSQNNNNN
MSMQ(微软)NNNNN
Kafka/JafkaYNNNY(Feature but not Supported)
  1. 以往对于kafka的吞吐量,是以at most once投递策略为测试基准的,这种策略下,不保证可靠性,大多数组件使用此策略,吞吐量都有大幅度提升
  2. kafka使用事务语义实现,并不直接支持amqp事务,这个特性体现在客户端程序中
  3. 多个消费者同时消费kafka时,根据其机制,需要确保offset的一致性,这时候需要引入其他设施来保证
  4. RocketMq事务支持完整,但是不支持Amqp,使用过程中,代码移植较麻烦
  5. 对于RocketMq的部署,有云服务,必须是有云服务,此类设置是不建议实用云主机搭建的,因为云主机基于内核虚拟化技术,I/O受制于cgroup,因此性能与物理主机相比,是大打折扣的,无法保证设施的最大性能
  6. RabbitMq缺乏消息对账机制,而使用事务和双向确认时,吞吐量无保证(换其他Mq也有同样问题)
  7. ActiveMq的集群,使用的是LevelDB数据库作为集群,而不是常见的mysql

对于一些设施细节的另类理解

  1. kafaka并不全面支持Amqp事务,对JMS支持也不是完整的。
  2. ActiveMQ是这些竞品中,性能最差的,但是也是功能最完整的。
  3. Rocket MQ的API和AMQP 没什么联系,消费端生产端,同时也是所有MQ中部署成本最高的。
  4. RabbitMQ部署简单,只是缺了消息对账。

参考 github.com/Snailclimb/…