浅析常见消息队列

消息队列常见的使用场景

  1. 解耦,比如A系统需要推送相同的数据给B系统和C系统,如果不使用mq,那么大致相同的逻辑我们要维护两份。假如未来某一天,又要对接n个系统或者取消对某个系统的推送,那么维护这个模块的人得疯,可扩展性比较差。同时,还要考虑其他系统的接口是否会访问超时或者直接访问不通,还得引入重试机制等。如果使用了mq,那么A系统只需将数据发送到队列中,其他系统根据自己的实际业务主动去订阅或者取消订阅该消息,这样就达到了解耦的目的,提高了可维护性。
  2. 异步,比如A系统某个接口需要调用三个外部接口,调用时间分别是100ms、150ms和150ms,那么A系统如果采用同步的方式响应时间至少大于400ms,大大超出了接口响应时间要求的200ms。那么如果我们采用异步的方式,通过mq去与其他的三个系统交互,A系统此接口的性能将大幅提升。
  3. 削峰,比如A系统每天访问的峰值是每小时千万级,而平均值
    每小时只有十万级。那么如果采用的是mysql数据库,1s最多处理2000条sql,1h最多处理数百万请求,如果同时千万级的流量进来,直接数据库就宕机了。为了数据库不被打死,保证可用性,可以把流量全部导入mq,消费者再慢慢的处理消息。

消息队列的缺点

  1. 引入mq可能会导致系统可用性降低,如果mq挂掉,与之关联的系统功能都会受影响,尤其是核心业务。
  2. 引入mq提高了系统的复杂性,包括消息的丢失、消息的重复发送和消息的幂等性、消息队列的可用性、消息导致的一致性问题和消息的顺序性等问题。

常见消息队列的区别

  • 主要从吞吐量、可用性、可靠性、功能是否完备、社区活跃度和技术架构角度分析。
  1. 吞吐量方面,ActiveMq和RabbitMq是每秒万级左右,RocketMq和Kafka是每秒10万级左右。
  2. 可用性,RocketMq和Kafka可靠性非常高,基于分布式架构;ActiveMq和RabbitMq也很高,基于主从架构实现。
  3. 可靠性,RocketMq和RabbitMq较低的概率会丢消息,RocketMq和Kafka通过配置可以做到消息0丢失。
  4. 功能完备方面,RabbitMq自带的监控功能比较不错,而Kafka的功能相对单一。
  5. 社区活跃度方面,目前ActiveMq相比较而言比较差。
  6. 技术架构方面,RocketMq和Kafka支持分布式,RabbitMq采用erLang语言开发,国内用的比较少。
  • 通过以上分析,Rabbitmq适用于中小型公司,主要靠社区维护;Rocketmq适用于大公司,采用java语言,一般有技术实力可以维护;Kafka是日志采集和大数据领域的事实标准。

如何保证高可用?

  • RabbitMq,普通集群模式通过队列元数据存储于所有节点,队列消息数据存储于单个节点实现,可以提高吞吐量,达不到高可用。缺点是产生大量数据传输。镜像集群模式,队列消息数据存储于多个节点实现,可以满足高可用。
  • Kafka0.8以后,集群通过副本机制,可以实现高可用。每个topic可以有多个partition,每个partition可以有多个副本,每个副本位于不同的机器。

如何保证消息不会丢失?

  • Rabbitmq,发送者通过事务机制可以保证生产者消息不丢失,但是会影响性能,通常选择异步confirm机制。Queue的持久化,只是持久化元数据,还需要消息的持久化。即使这样,未来得及落盘的消息,在Rabbitmq突然宕机的时候,也会丢失。消费者通过手动ack来保证数据不丢失。
  • Kafka,生产者如果配置不合理,将follower切换成leader时,会导致没同步的数据丢失。通过以下四个配置,可以保证生产者数据不丢失。消费者通过手动提交offset来保证数据不丢失。
    在这里插入图片描述

如何保证消费消息的幂等性

通过基于数据库的唯一键,或者逻辑层去重来保证唯一性,比如内存Set,或者查表。

如何保证消息的顺序性

  • RabbitMq,一个队列多个消费者,消息顺序无法保证;一个队列一个消费者,消息顺序就可以保证。
  • Kafka,基于写入一个partition的数据一定是顺序的,通过一个消费者只消费一个partition实现顺序性。
  • 注意消费者多线程处理也会导致消息错乱,可以类比消息中间件的思想,将线性的消息分段路由到不同的内存队列中,每个线程只处理一个内存队列,既可以保证吞吐量,又可以保证顺序性。

线上消息积压如何处理?

在这里插入图片描述
在这里插入图片描述