MQ 如何保证消息不丢失
哪些环节可能导致消息丢失
- 生产者向主节点发送消息
- 主节点向从节点同步消息
- MQ 数据持久化
- 消费者消费消息
生产者发送消息如何保证不丢失
生产者发送消息丢失的原因是因为网络的不稳定性。
- RocketMQ 通过同步和异步发送消息机制来保证发送消息的安全性。
同步:消息最安全,但是效率很低。
异步:消息安全和效率之间比较均衡,但会加大客户端的负担。因为消息发送后还要维护回调上下文,网络 IO 和内存负担会更高。
- RocketMQ 独有的事务消息机制也可以保证生产者安全发送消息
- kafka 也提供了类似的同步,异步发送消息机制。
- RabbitMQ 的 Publisher Confirms 生产者确认机制的思路也是 Publisher 收到 Broker 的响应后在执行对应的回调方法。
统一的思路是,给生产者响应,让生产者知道消息是否发送成功。
Broker写入数据如何保证不丢失
Producer 把消息发送给 Broker 后,消息会先写入到 Page Cache 缓存中,过一段时间再写入磁盘。如果写入磁盘之前断电,这些数据就丢失了。
- RocketMQ 通过配置参数支持同步刷盘和异步刷盘,同步刷盘也不是来一条数据刷一次,而是隔 10ms 刷一次,异步是隔 200ms。
- kafka 默认由系统控制刷盘时间。
- RabbitMQ 也是由系统控制刷盘时间,但是官方建议使用 Publisher Confirms 来确保消息安全。
Broker 主从同步如何保证不丢失
RocketMQ 主从集群
主节点和从节点都是确定的,如果主节点挂了,从节点也不会转化为主节点。所以这种方式主从同步不会丢失数据。
Deldger 高可用集群
基于 Raft 协议进行主从同步,使用多数派同意机制才可以将数据保存,保证集群内数据的一致性,但是不保证数据不丢失。虽然可能因为网络分区造成的脑裂问题使数据丢失,但是这个可能性很小。
kafka 集群
当主节点挂了,从节点会重新选取主节点,这时旧的主节点可能还有没有同步成功的数据,当旧的主节点恢复正常,发现集群里有主节点,会自动转化为从节点,并主动删除多余数据,这样那些还未同步的数据就丢失了。
消费者消费消息如何不丢失
一般的 MQ 产品都设置了消费者状态确认机制,如果消费者没有成功消费消息,Broker 会重新发送消息,因此,消费者消费消息还是比较安全的。
但是如果异步处理消息,就可能造成消息丢失。
MQ 如何保证消息的顺序性
- RocketMQ 将同一组消息放入同一个 MessageQueue 中。消费者锁定一个队列读取全部的消息之后再读取另一个队列。
- kafka 消费者是单线程模式,生产者按序将消息放入队列中,消费者就可以按序读取消息。
- RabbitMQ 在一个队列对应一个消费者的时候可以保证,但一个队列对应多个消费者不可以保证。
MQ 如何保证消息幂等性
生产者处理方式
- RocketMQ 在发送消息时,给每条消息分配一个唯一 ID。通过这个 ID,判断消息是否重复投递。
- kafka 可以通过打开幂等性配置来保证。
消费者处理方式
- RocketMQ 使用 key 属性存放唯一 ID,不依赖默认的唯一 ID。
MQ 如何快速处理积压的消息,
- 对于RabbitMQ,如果是 Classic Queue经典对列,针对同一个 Queue,直接加更多的Consumer实例就可以了。
- 对于RocketMQ,增加的 Consumer 实例最多也只能和 Topic 下的 MessageQueue 个数相同,因此不可以使用增加 Consumer 的方法。
如果要快速处理积压的消息,可以创建一个新的Topic,配置足够多的MessageQueue。然后把Consumer实例的Topic转向新的Topic,并紧急上线一组新的消费者,只负责消费旧Topic中的消息,并转存到新的Topic中。这个速度明显会比普通Consumer处理业务逻辑要快很多。然后在新的Topic上,就可以通过添加消费者个数来提高消费速度了。之后再根据情况考虑是否要恢复成正常情况。