RocketMQ专题总结

在这里插入图片描述

RocketMQ常见问题总结

1.RocketMQ的架构是怎么样的?

RocketMQ主要有Producer、Broker和Consumer三部分组成,如下图所示:

  1. Producer:消息生产者,负责将消息发送到Broker。
  2. Broker:消息中转服务器,负责存储和转发消息。RocketMQ支持多个Broker构成集群,每个Broker都拥有独立的存储空间和消息队列。
  3. Consumer:消息消费者,负责从Broker消费消息。
  4. NameServer:名称服务,负责维护Broker的元数据信息,包括Broker地址TopicQueue等信息。Producer和Consumer在启动时需要连接到NameServer获取Broker的地址信息。
  5. Topic:消息主题,是消息的逻辑分类单位。Producer将消息发送到特定的Topic中,Consumer从指定的Topic中消费消息。
  6. Message Queue:消息队列,是Topic的物理实现。一个Topic可以有多个Queue,每个Queue都是独立的存储单元。Producer发送的消息会被存储到对应的Queue中,Consumer从指定的Queue中消费消息。

2.介绍一下RocketMQ的工作流程

RocketMQ中有这样几个角色:NameServer、Broker、Producer和Consumer。

NameServer:它是RocketMQ的路由和寻址中心,维护了Broker和Topic的路由信息,提供了Producer和Consumer与正确的Broker建立连接的能力。NameServer还负责监控Broker的状态,并提供自动发现和故障恢复的功能。

Broker:它是RocketMQ的核心组件,负责存储、传输和路由消息。接收Producer发送的消息,并将其存储在内部存储结构中。并且负责Consumer的订阅请求,将消息推送给订阅了相应Topic的Consumer。

Producer:它是消息的生产者,用于将消息发送到RocketMQ系统。

Consumer:它是消息的消费者,用于从RocketMQ系统中订阅和消费消息。

RocketMQ工作工程大致如下:

  1. 启动NameServer,它会等待Broker、Producer以及Consumer的连接。
  2. 启动Broker,它会和NameServer建立连接,定时发送心跳包。心跳包中包含当前Broker信息(ip、port等)、Topic信息以及Broker与Topic的映射关系
  3. 启动Producer,启动时先随机和 NameServer集群中的一台建立长连接,并从NameServer中获取当前发送的Topic所在的所有Broker的地址;然后从队列列表中轮询选择一个队列,与队列所在的Broker建立长连接,进行消息的发送。
  4. Broker接收Producer发送的消息,当配置为同步复制时,master需要先将消息复制到slave节点,然后再返回“写成功状态”响应给生产者;当配置为同步刷盘时,则还需要将消息写入磁盘中,再返回“写成功状态”;若配置的是异步刷盘和异步复制,则消息只要发送到master节点,就直接返回“写成功状态”。
  5. 启动Consumer,过程和Producer类似,先随机和一台NameServer建立连接,获取订阅信息,然后再和需要订阅的Broker建立连接,获取消息。

3.RocketMQ怎么实现消息分发的?

RocketMQ支持两种消息模式:广播消费(Broadcasting)集群消费(Clustering)

广播消费: 当使用广播消费模式时,RocketMQ会将每条消息推送给集群内所有的消费者,保证消息至少被每个消费者消费一次。

广播模式下,RocketMQ保证消息至少被客户端消费一次,但是并不会重投消费失败的消息,因此业务方需要关注消费失败的情况。并且,客户端每一次重启都会从最新消息消费。客户端再被停止期间发送至服务端的消息将会被自动跳过。

集群消费: 当使用集群消费模式时,RocketMQ认为任意一条消息只需要被集群内的任意一个消费者处理即可。

集群模式下,每一条消息都只会被分到一台机器上处理。但是不保证每一次失败重投的消息路由到同一台机器上。一般来说,用集群消费的更多一些。

可以通过设置MessageModel调整消费方式:

// 设置为集群模式,默认为集群模式
properties.put(PropertyKeyConst.MessageModel, PropertyValueConst.CLUSTERING);
// 设置为广播模式
properties.put(PropertyKeyConst.MessageModel, PropertyValueConst.BROADCASTING);

4.RocketMQ如何保证消息的顺序性?

RocketMQ提供了基于队列的顺序消费。即同一个队列内的消息可以做到有序,但是不同队列内的消息是无序的。

生产者发送顺序消息:若想要发送顺序消息,生产者需要在send方法中传入一个MessageQueueSelector。MessageQueueSelector中需要实现一个select方法,这个方法就是用来定义把消息发送到哪个MessageQueue的,通常可以使用取模法进行路由。

消费者按顺序消费:RocketMQ的MessageListener回调函数提供了两种消费模式,有序消费模式MessageListenerOrderly和并发消费模式MessageListenerConcurrently。若想实现顺序消费,需要使用MessageListenerOrderly模式接收消息。消费者拉取消息前,需要向Broker申请为当前消费者客户端申请分布式锁。若获取成功,那么后续消息将会只发送给这个Consumer,保证Broker只会把消息发送到同一个消费者上。然后Consumer会一次性拉取多条消息放入ProcessQueue中,同时将消息提交到消费线程池进行执行。

消费过程如何保证顺序消费: 消费过程中,需要申请MessageQueue锁,确保在同一时间,一个队列中只有一个线程能处理队列中的消息。获取到锁后,就可以从ProcessQueue中依次拉取一批消息进行处理,为了保证消息不会出现重复消费,需要对ProcessQueue进行加锁。

总结: 加了三次锁,先锁定Broker上的MessageQueue,确保消息只会投递到唯一的消费者;然后对本地的MessageQueue加锁,确保只有一个线程能处理这个消息队列。最后对存储消息的ProcessQueue进行加锁,确保在重平衡的过程中不会出现消息的重复消费。

5.RocketMQ如何保证消息不丢失?

生产者端: 消息发送分为同步和异步两种。

首先,同步发送消息情况下,消息的发送会同步阻塞等待Broker返回结果,在Broker确认收到消息后,生产者才会拿到SendResult。若这个过程中发生了异常,说明消息可能发送失败,需要生产者重新发送消息。

当Broker收到消息后又会划分两种情况,第一种是异步刷盘,就是收到消息后,先存储到内存中,然后返回确认结果给生产者。然后再通过异步刷盘的方式将消息存储到磁盘上,但是这个过程中如果Broker机器挂了,那么可能会导致数据丢失。

如果像保证消息不丢失,可以将消息保存机制修改为同步刷盘,这样Broker会在同步请求中把数据保存在磁盘上,确保保存成功后再返回确认结果给生产者。

其次是异步发送消息,异步发送的话需要生产者重写SendCallback的onSuccess和onException方法,用于给Broker进行回调。在方法中实现消息的确认或者重新发送。

Broker端: 为了保证消息不丢失,RocketMQ最好通过集群方式进行部署,Broker通常采用一主多从部署方式,并且采用主从同步的方式做数据复制。主Broker宕机的话,从Broker会接管主Broker的工作,保证消息不丢失。默认方式下,Broker在接收消息后,写入master成功,就可以返回确认响应给生产者了,接着消息将异步复制到slave节点。但是这个过程中,若Master宕机,就可能导致数据丢失。可以配置同步复制的方式解决,即Master在将数据同步到Slave节点后,再返回给生产者确认结果。

消费者端: 消费者端需要确保在消息拉取并消费成功之后再给Broker返回ACK,就可以保证消息不丢失了,如果这个过程中Broker一直没收到ACK,那么就重试。

6.RocketMQ如何实现延时消息?

RocketMQ支持延时消息,延时消息写入到Broker后,不会立刻被消费者消费,而是等待指定时长后才可以被消费处理。

当消息发送到Broker后,Broker会将消息根据延迟级别进行存储。RocketMQ的延迟消息实现方式是:将消息先存储在内存中,然后使用Timer定时器进行消息的延迟,到达指定时间后再存储到磁盘中,最后投递给消费者。

RocketMQ并不是支持任意时长的延迟的,只支持(5.0之前):1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h这些时长。

基于Timer定时器来实现延迟投递时,由于Timer定时器是有一定缺陷的,当定时器中有大量任务时,会导致定时器性能下降,从而影响消息投递。在RocketMQ5.0中,采用了一种新的实现方式:基于时间轮的定时消息。时间轮是一种高效的定时器算法,能够处理大量的定时任务,并且能够在O(1)时间内找到下一个即将要执行的任务,因此能够提高消息的投递性能。并且基于时间轮的定时消息能够支持更高的消费精度,可以实现秒级、毫秒级甚至更小时间粒度的定时消息。

具体实现方式如下:

  1. RocketMQ在Broker端使用一个时间轮来管理定时消息,将消息按照过期事件放置在不同的槽位中,这样可以大幅减少定时器任务的数量。
  2. 时间轮的每个槽位对应一个时间间隔,比如1s、5s、10s等,每次时间轮的滴答,槽位向前移动一个时间间隔。
  3. 当Broker接收到定时消息时,根据消息的过期时间计算出需要投递的槽位,并将消息放置到对应的槽位中。
  4. 当时间轮的滴答到达消息的过期时间时,时间轮会将该槽位中的所有消息投递给消费者。

使用方式:

// 创建一个消息生产者
DefaultMQProducer producer = new DefaultMQProducer("test1");
producer.setNamesrvAddr("localhost:9876");
producer.start();

Message message = new Message("TopicTest", "TagA", "HelloWorld".getBytes(RemotingHelper.DEFAULT_CHARSET));
// 设置消息的延迟级别为3,即延迟10秒
message.setDelayTimeLevel(3);

// 消息发送
SendResult sendResult = producer.send(message);
System.out.printf("%s%n", sendResult);

7.RocketMQ有几种集群方式?

RocketMQ有3种集群模式,分别是单Master模式多Master模式以及多Master多Slave模式

单Master集群: 只包含一个Master节点和若干个Slave节点。所有的写入操作都由Master节点负责处理,Slave节点主要用于提供读取服务。当Master节点宕机时,集群将无法继续工作。

多Master集群: 这种集群模式包含多个Master节点,不部署Slave节点。这种方式优点是配置简单,单个Master宕机或重启维护对应用无影响,在磁盘配置为RAID10时,即使机器宕机不可恢复情况下,由于RAID10磁盘非常可靠,消息也不会丢失(异步刷盘丢失少量消息,同步刷盘一条不丢),性能最高;缺点是单台机器宕机期间,这台机器上未被消费的消息在机器恢复之前不可订阅,消息 实时性会收到影响。

多Master多Slave集群: 这种集群方式包含多个Master节点和多个Slave节点。每个Master节点都可以处理写入操作,并且有自己的一组Slave节点。当其中一个Master节点宕机时,消费者仍然可以从Slave消费。优点是数据与服务都无单点故障,Master宕机情况下,消息无延迟,服务可用性与数据可用性都非常高;缺点是性能比异步复制模式略低,发送单个消息的延迟会略高,目前版本在主节点宕机后,备机不能自动切换为主机。

8.RocketMQ消息堆积了怎么解决?

RocketMQ的消息堆积,一般都是因为客户端本地消费过程中,由于消费耗时过长或消费并发度较小等原因,导致客户端消费能力不足,出现消息堆积的问题。解决方案:

  1. 增加消费者数量
  2. 提升消费者消费速度:引入线程池、本地消息存储后即返回成功后续再慢慢消费等
  3. 降低生产者的生产速度
  4. 清理过期消息
  5. 调整RocketMQ的配置参数:根据实际情况调整消息消费模式、消息拉取间隔时间等,从而优化消息消费的效率
  6. 增加Topic队列数

9.RocketMQ的消息是推还是拉?

MQ的消费模式大致可分为两种,一种是推Push,一种是拉Pull。

Push是服务端主动推送消息给客户端,Pull是客户端需要主动到服务端轮询获取数据。

推模式的优点是实时性较好,但如果客户端没有做好流控,一旦服务端推送大量消息到客户端,会导致客户端消息堆积。

拉模式优点是客户端可以根据自己的消费能力进行消费,但是频繁拉取会给服务端造成压力,并且可能会导致消息消费不及时。

RocketMQ既提供了Push模式也提供了Pull模式,主要有两个Consumer可以供开发者选择,DefaultMQPullConsumer、DefaultMQPushConsumer。

10.RocketMQ的事务消息是如何实现的?

RocketMQ的事务消息是通过TransactionListener接口来实现的。在发送事务消息时,首先向RocketMQ Broker发送一条“half消息”(半消息),半消息将被存储在Broker端的事务消息日志中,但是这个消息还不能被消费者消费。当半消息发送成功后,应用程序通过执行本地事务来确定是否要提交该事务消息。如果本地事务执行成功,就会通知RocketMQ Broker提交该事务消息,使得该消息可以被消费者消费;否则,就会通知RocketMQ Broker回滚该事务消息,该消息将被删除,从而保证消息不会被消费者消费。

  • 38
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值