常见消息队列分析对比

1,065 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第12天,点击查看活动详情

消息队列

应用场景

  • 应用解耦,比如,用户下单后,订单系统需要通知库存系统,假如库存系统无法访问,则订单减库存将失败,从而导致订单失败。订单系统与库存系统耦合,这个时候如果使用消息队列,可以返回给用户成功,先把消息持久化,等库存系统恢复后,就可以正常消费减去库存了。
  • 削峰填谷,比如,秒杀活动,一般会因为流量过大,从而导致流量暴增,应用挂掉,这个时候加上消息队列,服务器接收到用户的请求后,首先写入消息队列,假如消息队列长度超过最大数量,则直接抛弃用户请求或跳转到错误页面。
  • 日志系统,比如,客户端负责将日志采集,然后定时写入消息队列,消息队列再统一将日志数据存储和转发。

1.Kafaka、RabbitMQ、RocketMQ之间的区别是什么?

  • 性能:消息中间件的性能主要衡量吞吐量
    • RabbitMQ单机QPS在万级别
    • Kafaka单机QPS能够达到百万级别
    • RocketMQ单机写入TPS单实例约7万条/秒,单机部署3各Broker,可以跑到最高12万条/秒,消息大小10个字节。
  • 数据可靠性:Kafaka与RabbitMQ都具备多副本机制,数据可靠性较高,RocketMQ支持实时异步刷盘,同步刷盘,同步Replication,异步Replication。
  • 服务可用性:Kafaka采用集群部署,分区与多副本的设计,使得单节点宕机对服务无影响,且支持消息容量的线性提升。RabbitMQ支持集群部署,集群节点数量有多种规格。RocketMQ是分布式架构,高可用。

2.Kafaka的架构

  • kafaka的架构包括3个角色:
    • 生产者(Producer):消息和数据的生产者。
    • 代理(Broker):缓存代理,Kafaka的核心功能。
    • 消费者(Consumer):消息和数据消费者。
  • Kafaka给Producer和Consumer提供注册的接口,数据从Producer发送到Broker,Broker承担一个中间件缓存和分发的作用,负责分发注册到系统中的Consumer。
  • Kafaka数据保留策略:按照过期时间保留和按照存储的消息大小保留。

3.Kafaka怎么保证消息是有序的?

  • 消息在被迫追加到Partition(分区)的时候都会分配一个特定的偏移量(offset)。Kafaka通过偏移量(offset)来保证消息在分区内的顺序性。
    • 一个Topic只对应一个Partition
    • 发送消息的时候指定key/partition

4.Kafaka怎么保证消息不丢失?

  • 生产者丢失消息的情况:消息可能在发送的过程中由于网络问题导致消息没有发送成功。Kafaka生产者发送消息send实际上是异步操作,如何保证消息发送成功:
    • 通过调用get方法获取发送结果,但是这样就变为了同步操作影响性能。一般不推荐之间使用get方式,而是采用回调函数,在回调函数里检查失败原因在做重发。
    • 设置Producer的retries(重试次数)一个合理值,一般为3,但是为了保证消息不丢失可以设置的大一点,如此设置后,当出现网络原因消息没有发送成功会自动重发。还需要设置重发时间间隔,一般重试的间隔时间不要太短,时间太短重试的效果就不明显了。
  • 消费者丢失消息的情况:消费者拉到某个分区的消息后消费者会自动提交offset。这样就会产生一个问题,消费者自动提交offset后但是还没真正消费服务突然挂掉了,这种情况消息实际上是没有被消费的。所以只需要关闭消费者自动提交offset,在每次真正消费完成后在进行手动提交offset。这样又可能出现真正消费完成了但是手动提交offset失败了,就有可能导致消息重复消费。(可通过幂等处理)
  • Kafaka弄丢消息:在leader副本所在的broker突然挂掉的时候,那么就要从follower副本重新选出一个leader,但是leader还有一些数据没有被follower同步,就会造成消息丢失。解决方法是设置unclean.leader.election.enable=false,当leader副本发生故障的时候,就不会选择follower和leader同步程度达不到要求的副本作为新的leader,这样就降低了消息丢失的可能性。

5.Kafaka多副本机制

Kafaka分区中多个副本之间会有一个leader,其他副本称为follower,我们发送的消息会被发送到leader,然后follower才能从leader拉取消息进行同步。 生产者和消费者只与leader副本进行交互,其他副本存在只为了保证消息存储的安全性。当leader发生故障的时候会从follower中选出一个leader,如果follower中有和leader同步程度达不到要求的就不能参与leader竞选。

6.RabbitMQ

  • RabbitMQ有哪些角色
    • 生产者:消息的创建者,负责创建消息和推送消息到服务器。
    • 消费者:消息的接收方,用于处理消息和确认消息。
    • 代理:RabbitMQ本身,相当于扮演了“快递”角色。
  • RabbitMQ的重要组件
    • ConnectionFactory(连接管理器):应用程序与RabbitMQ服务器之间建立连接的管理器。
    • Channel(信道):消息推送的通道。
    • Exchange(交换机):用于接收和分配消息。
    • Queue(队列):用于存储生产者产生的消息。
    • RoutingKey(路由key):用于把生产者生成的数据分配到交换机上。
    • BindingKey(绑定key):用于把交换机的消息绑定到队列上。

image.png

7.RabbitMQ消息消费问题

  • 如何确保消息被消费
    • 关闭自动ack
    • 在接收到消息并处理完成后,使用channel.basicAck()进行手动消息确认。
  • 消费者接收到消息必须消费吗
    • 订阅者接收到消息后可以选择拒绝消费:channel.basicReject(id, true),mq会将消息分配给其他订阅者。
    • 设置死信队列,死信队列是专门用于存放被拒绝的消息队列。

8.RabbitMQ事务

  • 事务使用方式有三种,主要是针对信道的设置,如下:
    • 声明启动事务模式:channel.txSelect()
    • 提交事务:channel.txCommit()
    • 回滚事务:channel.txRollback()
  • 什么情况下事务无效:autoAck=true,开启自动消息确认的时候,事务是无效的。因为自动消费确认的时候,mq会直接把消息从队列中移除,即使有事务回滚也没用。

9.RabbitMQ如何保证消息不丢失?

  • 开启RabbitMQ事务(同步,性能差)
  • 开启confirm模式(异步,性能好)
    • MQ:Exchange持久化、queue持久化、消息持久化
    • 消费者:关闭自动ack