From 29a711a542656e665cf1de98e5f60352dc9bf228 Mon Sep 17 00:00:00 2001 From: TheBestFlyingPig <115528918+TheBestFlyingPig@users.noreply.github.com> Date: Fri, 4 Nov 2022 16:34:44 +0800 Subject: [PATCH] docs: supplement RocketMQ's message consumption failure scenarios and common solutions (#280) --- ...e-the-reliable-transmission-of-messages.md | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md b/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md index ab56eb6..69eff3f 100644 --- a/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md +++ b/docs/high-concurrency/how-to-ensure-the-reliable-transmission-of-messages.md @@ -165,3 +165,44 @@ RabbitMQ 如果丢失了数据,主要是因为你消费的时候,**刚消费 #### 生产者会不会弄丢数据? 如果按照上述的思路设置了 `acks=all` ,一定不会丢,要求是,你的 leader 接收到消息,所有的 follower 都同步到了消息之后,才认为本次写成功了。如果没满足这个条件,生产者会自动不断的重试,重试无限次。 + +### RocketMQ + +#### 消息丢失的场景 + +1. 生产者发送消息到 MQ 有可能丢失消息 +2. MQ 收到消息后写入硬盘可能丢失消息 +3. 消息写入硬盘后,硬盘坏了丢失消息 +4. 消费者消费 MQ 也可能丢失消息 +5. 整个 MQ 节点挂了丢失消息 + +#### 生产者发送消息时如何保证不丢失? + +解决发送时消息丢失的问题可以采用 RocketMQ 自带的**事物消息**机制 + +事物消息原理:首先生产者会发送一个**half 消息**(对原始消息的封装),该消息对消费者不可见,MQ 通过 ACK 机制返回消息接受状态, 生产者执行本地事务并且返回给 MQ 一个状态(Commit、RollBack 等),如果是 Commit 的话 MQ 就会把消息给到下游, RollBack 的话就会丢弃该消息,状态如果为 UnKnow 的话会过一段时间回查本地事务状态,默认回查 15 次,一直是 UnKnow 状态的话就会丢弃此消息。 + +为什么先发一个 half 消息,作用就是先判断下 MQ 有没有问题,服务正不正常。 + +#### MQ 收到消息后写入硬盘如何保证不丢失? + +数据存盘绕过缓存,改为同步刷盘,这一步需要修改 Broker 的配置文件,将 flushDiskType 改为 SYNC_FLUSH 同步刷盘策略,默认的是 ASYNC_FLUSH 异步刷盘,一旦同步刷盘返回成功,那么就一定保证消息已经持久化到磁盘中了。 + +#### 消息写入硬盘后,硬盘坏了如何保证不丢失? + +为了保证磁盘损坏导致丢失数据,RocketMQ 采用主从机构,集群部署,Leader 中的数据在多个 Follower 中都存有备份,防止单点故障导致数据丢失。 + +Master 节点挂了怎么办?Master 节点挂了之后 DLedger 登场 + +- 接管 MQ 的 commitLog +- 选举从节点 +- 文件复制 uncommited 状态 多半从节点收到之后改为 commited + +#### 消费者消费 MQ 如何保证不丢失? + +1. 如果是网络问题导致的消费失败可以进行重试机制,默认每条消息重试 16 次 +2. 多线程异步消费失败,MQ 认为已经消费成功但是实际上对于业务逻辑来说消息是没有落地的,解决方案就是按照 mq 官方推荐的先执行本地事务再返回成功状态。 + +#### 整个 MQ 节点挂了如何保证不丢失? + +这种极端情况可以消息发送失败之后先存入本地,例如放到缓存中,另外启动一个线程扫描缓存的消息去重试发送。