MQ 聊聊消息队列那些事( 二 )


  • MQ丢失消息消息成功发送到MQ,是先放到内存里的,如果还没来得及给消费者消费消息 , MQ服务就挂了,就会丢失消息 。这个问题一方面可以做集群,但集群的数据同步也需要一定时间,如果在同步数据之前就MQ服务挂了,消息也会丢失 。还有一个方法就是MQ接收到消息的同时 , 把消息数据持久化到磁盘,这样,MQ服务恢复的时候就可以从磁盘获取数据重新给消费者消费 。可能有人会问,那消息还没来得及持久化到磁盘MQ服务就挂了咋办?如果是这样,就可以用到前面说到的本地消息表,把本地消息表里的数据重新发一遍 。?
  • 消费者丢失消息消费者从MQ拉取消息,还没来得及处理消息,消费者服务器挂了 。此时,可能造成消费者丢失消息 。这种情况,可以让消费者处理完消息时给MQ一个确认消息来解决 。如果MQ没有收到确认消息,就会有重试的机制,最终确保消息给到消费者消费 。当然了,如果重试超过一定次数,就应该告警,人工介入 。
  • 问题三:重复消费因为在网络延迟的情况下,消息重复发送的问题不可避免的发生 。譬如,生产者发送消息的时候使用了重试机制,发送消息后由于网络原因没有收到MQ的确认信息,然后又去重新发送了一次消息 。但其实MQ已经接到了消息,并返回了响应,只是因为网络原因导致生产者没有收到MQ的确认信息 。这种情况下,生产者的消息重试机制就会继续就这个消息重新发送,从而导致同一条消息多次发送 , 这样消费者也会重复消费这条消息 。当然,这只是列举了一种情况,实际上还有其他情况会导致消息被重复消费 。
    解决重复消费的关键就是在消费者端引入幂等性机制 。什么是幂等性机制呢?我们可以把它理解成,假如一个接口被重复调用,依然可以保证数据的准确性 。举个例子,比如每条消息都会有一条唯一的id,消费者处理完这个消息会存储这个id,如果处理消息之前能找到这个id,就说明这条消息已经处理过了,就不做处理并且返回给MQ一个确认信息 。
    消息队列中间件为什么要用消息队列中间件?自己写不行吗?我们之所以要用中间件,是因为这些中间件已经解决了很多消息队列常见的问题(高可用、消息丢失、重复消费......) , 而且各种中间件都有各自的特性,已经做得非常成熟了 , 你确定你写的有这些中间件好用吗?
    目前在市面上比较主流的MQ中间件主要有,Kafka、ActiveMQ、RabbitMQ、RocketMQ 等这几种 。网上找来这几个中间件的对比,如下表:
    特性ActiveMQRabbitMQKafkaRocketMQ所属社区/公司ApacheMozilla Public LicenseApacheApache/Ali单机淄铝?/td>万级(最差)万级十万级十万级(最高)时效性毫秒级微秒级毫秒级毫秒级可用性高(主从)高(主从)非常高(分布式)非常高(分布式)功能特性MQ领域功能极其完备基础erlang开发 , 所以并发能力很强,性能极其好 , 延时很低功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用MQ功能比较完备 , 扩展性佳消息可靠性有较低的概率丢失数据基本不丢经过参数优化配置,可以做到 0 丢失同 Kafka事务支持不支持支持支持broker端消息过滤支持不支持不支持可以支持Tag标签过滤和SQL表达式过滤消息查询支持根据消息id查询不支持支持Message id或Key查询消息回溯支持不支持理论上可以支持时间或offset回溯 , 但是得修改代码 。支持按时间来回溯消息,精度毫秒,例如从一天之前的某时某分某秒开始重新消费消息 。路由逻辑基于交换机 , 可配置复杂路由逻辑根据topic根据topic,可以配置过滤消费持久化内存、文件、数据库队列基于内存 , 只能少量堆积磁盘,大量堆积磁盘,大量堆积顺序消息支持不支持支持支持社区活跃度低中高高适用场景主要场景就是解耦和异步调用,较少在大规模吞吐的场景中使用数据量没有那么大,小公司一般配合大数据类的系统来进行实时数据计算、日志采集等场景 。目前在阿里被广泛应用在订单、交易、充值、流计算、消息推送、日志流式处理、binglog分发消息等场景 。根据上表,我个人认为对性能要求比较高的 , 推荐选择RocketMQ,毕竟经历了多年阿里双十一极端并发的场景 。如果是大数据领域的,可以选择Kafka 。
    【MQ 聊聊消息队列那些事】

    推荐阅读