消息队列(mq)

Posted by Solace Blog on March 28, 2019

MQ

MQ的作用

  • 解耦:将各个系统解耦,降低各系统之间的耦合性。
  • 异步:之前的一个业务操作可能需要整个操作完成后返回一个结果,整个操作完成很耗时。使用mq后可以将请求放到队列中,让消费者去队列消费对应的消息。对于用户来说提升了用户体验。
  • 削峰:高峰期大量操作涌入系统会导致数据库崩溃,使用mq后可以将大量请求放入队列中,让系统从队列中根据最高可操作的请求数量来拉取请求来处理,这样可以使系统在高峰期也不会挂掉,等高峰一过就会消费多积压的消息

MQ的优点和缺点

  • 系统可用性降低

    MQ一旦故障,其他系统就没法收到消息,导致整个系统无法运转了

  • 系统复杂性提高

    需要考虑更多可能出现的问题,MQ消息丢了,MQ消息顺序出问题了,MQ积压大量消息。

  • 一致性问题

    系统ABC执行成功了,但是系统D执行失败了,但是返回的结果却是成功,实际后台数据是有问题的。

Kafka、ActiveMQ、RabbitMQ、RocketMQ之间的差异

特性 ActiveMQ RabbitMQ RocketMQ Kafka
单机吞吐量 万级吞吐量,比RocketMQ和Kafka低一个等级 万级,吞吐量比RocketMQ和Kafka低一个等级 10万级 10万级
topic数量对吞吐量的影响     topic可以达到成百上千个,吞吐量有小幅度下降 topic从几十到几百个,吞吐量会大幅度下降
时效性 ms级 微妙级 ms级 ms级
可用性 高,基于主从架构实现高可用 高,基于主从架构实现高可用 非常高,分布式架构 非常高,分布式架构
消息可靠性 较低的概率丢失数据   经过参数配置可以达到0丢失 经过参数配置可以达到0消息丢失
功能支持 MQ领域的功能极其完备 高并发性能,延时低 扩展性好 功能简单,支持简单的MQ功能,大数据领域使用较多
优劣势总结 非常成熟,功能强大,偶尔会有数据丢失,官方维护较少 性能极其好,延时低,有开源管理界面,社区活跃 接口简单,性能好,吞吐量大,文档简单 仅仅提供较少的核心功能,但是提供超高的吞吐量和ms级的延迟,唯一劣势可能会重复消费消息,但是这点影响在大数据处理中可以忽略不计

所以对于一般小公司而言,可以考虑使用RabbitMQ或者RocketMQ都可以,如果对自己实力绝对有自信,那么推荐使用RocketMQ,因为阿里提供了源码,可以定制适合自己的MQ。

如何保证消息队列的高可用

rabbitMQ:

  • 单机模式

  • 普通集群模式

    多个机器来提供队列服务,提高了吞吐量,由于一个queue只会在集群中的某一个机器上存在,所以也有两个主要缺点:可能会在rabbitMQ集群内部产生大量的数据传输;可用性几乎没有保障,如果存储queue的机器宕机了,那就没法消费了

  • 镜像集群模式

    每个queue的全部数据会在集群中的每个节点都会存在,任何节点宕机了都不会对消息产生影响,所以消费者任何节点消费都没有问题。

如何保证消息不被重复消费?

解决方案:

保证MQ重复消费的幂等性,一条消息重复出现两次,但数据库中只有一条数据,无论请求多少次都只有一条数据。

每次消费一条消息后,对消息记录一下,比如存到表里或者内存set中来记录一下,每次消费前查询一下有没有记录过,有记录说明之前已经被消费过了,就不用再往下走了。

保证消息的可靠性传输(如何处理消息丢失的问题)(RabbitMQ)

  • 生产者写消息的过程中,没有正常的存储到RabbitMQ中

    可以捕获异常后再继续发送消息,但是方法是阻塞的,效率低,不建议使用。

    将channel设置为confirm模式,在消息发送完后,无论成功或失败都会有对应的回调方法来执行后续操作,不会阻塞请求。

  • RabbitMQ接收到消息后先暂存到内存中,还没来得及消费,RabbitMQ挂掉了

    创建queue的时候将其设置为持久化的,同时在发送消息的时候讲消息的deliveryMode设置为2来将消息设置为持久化,必须同时设置这两个持久化才行。哪怕RabbitMQ挂掉了当它重启后才不会丢失消息

  • 消费者消费到了消息,但是还没来得及处理自己挂掉了

    RabbitMQ默认打开了autoAck的机制,我们首先关闭autoAck机制,每次消费处理完一个消息后手动发送ack给MQ

保证消息的顺序性

如果有三条数据想通过三个消费者按照顺序来插入到数据库中,但是由于三个消费者执行顺序的不同导致入库的顺序有误。

对于RabbitMQ而言,解决办法是,每个queue(队列)对应一个消费者,将需要执行的操作放入对应的队列中让消费者按顺序去消费。

消息队列积压过多消息(消费端出问题了)

假如有三个消费者,一个消费者一秒处理1000个请求,三个消费者一秒3000个请求,一分钟18w请求,一小时就处理1000w+个请求。如果积压了千万条请求,那就得花大概一小时来处理请求。