RocketMQ生产环境常见问题分析与总结
如何保证消息不丢失
- 消息丢失场景
- 对于跨网络的节点可能会丢消息,因为MQ存盘都会先写入OS的PageCache中,然后再让OS进行异步刷盘,如果缓存中的数据未及时写入硬盘就会导致消息丢失
- 生产端到Broker端
- Broker端主从同步
- Broker端到消费端
- 对于跨网络的节点可能会丢消息,因为MQ存盘都会先写入OS的PageCache中,然后再让OS进行异步刷盘,如果缓存中的数据未及时写入硬盘就会导致消息丢失
- 消息零丢失方案
- 生产端使用事务机制
- 当生产端将消息发送到Broker端,Broker端持久化之后会给生产端进行反馈,此时的消息处于半事务消息,生产端执行本地事务根据执行结果向Broker端提交二次确认来判断是否提交以及回滚,此时如果生产端出现故障,Broker端未收到二次确认,会通过回查机制进行生产端实例回查,生产端收到回查后会继续向Broker端进行二次确认
- 同步刷盘以及P2C两阶段提交(与ZAB机制类似)保证MQ主从同步时不会丢消息(同步刷盘 + Dledger主从架构)
- 同步刷盘
- P2C两阶段提交
- 基于Raft协议完成
- leader收到的消息会被标记为未提交然后同步给其它follower,follower收到消息后向leader反馈,当leader收到过半的follower的反馈之后才会将消息标记为已提交并且同步给其它follower
- 基于Raft协议完成
- 消费者端不要使用异步消费机制
- 在同步消费情况下,消费完消息之后再去给Broker端反馈,然后Broker端会去维护消息偏移量,如果消费失败可以进行一定次数的重试
- 在异步消费情况下,消费完消息的同时也会向Broker端反馈,然后Broker端会去维护消息偏移量,如果处理失败了,不会进行重试因为偏移量已经变更
- MQ服务端挂了采用降级方案(必须有)
RocketMQ特有的问题,NameServer挂了如何保证消息不丢失
- NameServer在RocketMQ中扮演路由中心的角色,提供Broker的路由功能,所有MQ都需要路由中心的功能
- 在Kafka中使用ZK和作为核心控制器的Broker一起来提供路由服务
- 在RabbitMQ中是由每一个Broker来提供路由服务的
- 在RockertMQ中单独抽取服务作为路由中心
- 对于RocketMQ来说,NameServer挂了,本身就无法保证消息不丢失了,所以应对这种场景,我们可以使用服务降级方案,将消息暂存到Redis、文件或内存中,等MQ服务恢复之后再将消息转移过去
- NameServer在RocketMQ中扮演路由中心的角色,提供Broker的路由功能,所有MQ都需要路由中心的功能
- 生产端使用事务机制
如何保证消息有序
-
MQ的顺序包含局部有序和全局有序
-
局部有序:(只保证一部分消息链路消费有序)
- 生产端可以通过消息选择器指定发送到某个MessageQueue,从而保证局部有序
-
全局有序:(整个消息链路严格按照先进先出的顺序进行消费)
- 要保证全局有序就必须牺牲吞吐量,也就是一个topic只能有一个MessageQueue被消费(默认4个),可以通过锁队列的方式进行消费,保证全局有序
-
如何快速处理积压消息
-
对于Kafka和RocketMQ消息积压并不会对性能有太大的影响,但是对于RabbitMQ就会导致性能直线下降
-
如何确定RocketMQ有大量的消息积压
- 对于RocketMQ可以通过控制台查看消息的积压情况
-
如何处理大量积压的消息
- 通过增加消费者去加快消费
- 如果Topic下的MessageQueue配置充足,那每个消费者会分配多个MessageQueue进行消费,所以可以增加消费者数加快消息消费,
- 如果消费者数 = MessageQueue数,此时增加额外的消费者效果是没有的,此时可以通过新建一个新的Topic配置足够的MessageQueue,将旧Topic中的消息转移到新Topic中,并且指定对应数量的消费者去平摊新Topic的MessageQueue去进行消费,之后再根据情况恢复原有情况
- Topic_A -> Consumer_A => Topic_A -> Consumer_A -> Topic_B -> Consumer_B
- 通过增加消费者去加快消费