Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Supplement RocketMQ's message consumption failure scenarios and common solutions #280

Merged
merged 3 commits into from
Nov 4, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Update how-to-ensure-the-reliable-transmission-of-messages.md
  • Loading branch information
yanglbme authored Nov 4, 2022
commit 8c56cecab8c8c90a98c39269eaa7bc4eacbf4195
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ while (true) {

设置持久化有**两个步骤**:

- 创建 queue 的时候将其设置为持久化。这样就可以保证 RabbitMQ 持久化 queue 的元数据,但是它是不会持久化 queue 里的数据的。
- 创建 queue 的时候将其设置为持久化。这样就可以保证 RabbitMQ 持久化 queue 的元数据,但是它是不会持久化 queue 里的数据的。

- 第二个是发送消息的时候将消息的 `deliveryMode` 设置为 2。就是将消息设置为持久化的,此时 RabbitMQ 就会将消息持久化到磁盘上去。
- 第二个是发送消息的时候将消息的 `deliveryMode` 设置为 2。就是将消息设置为持久化的,此时 RabbitMQ 就会将消息持久化到磁盘上去。

必须要同时设置这两个持久化才行,RabbitMQ 哪怕是挂了,再次重启,也会从磁盘上重启恢复 queue,恢复这个 queue 里的数据。

Expand Down Expand Up @@ -155,10 +155,10 @@ RabbitMQ 如果丢失了数据,主要是因为你消费的时候,**刚消费

所以此时一般是要求起码设置如下 4 个参数:

- 给 topic 设置 `replication.factor` 参数:这个值必须大于 1,要求每个 partition 必须有至少 2 个副本。
- 在 Kafka 服务端设置 `min.insync.replicas` 参数:这个值必须大于 1,这个是要求一个 leader 至少感知到有至少一个 follower 还跟自己保持联系,没掉队,这样才能确保 leader 挂了还有一个 follower 吧。
- 在 producer 端设置 `acks=all` :这个是要求每条数据,必须是**写入所有 replica 之后,才能认为是写成功了**。
- 在 producer 端设置 `retries=MAX` (很大很大很大的一个值,无限次重试的意思):这个是**要求一旦写入失败,就无限重试**,卡在这里了。
- 给 topic 设置 `replication.factor` 参数:这个值必须大于 1,要求每个 partition 必须有至少 2 个副本。
- 在 Kafka 服务端设置 `min.insync.replicas` 参数:这个值必须大于 1,这个是要求一个 leader 至少感知到有至少一个 follower 还跟自己保持联系,没掉队,这样才能确保 leader 挂了还有一个 follower 吧。
- 在 producer 端设置 `acks=all` :这个是要求每条数据,必须是**写入所有 replica 之后,才能认为是写成功了**。
- 在 producer 端设置 `retries=MAX` (很大很大很大的一个值,无限次重试的意思):这个是**要求一旦写入失败,就无限重试**,卡在这里了。

我们生产环境就是按照上述要求配置的,这样配置之后,至少在 Kafka broker 端就可以保证在 leader 所在 broker 发生故障,进行 leader 切换时,数据不会丢失。

Expand All @@ -170,38 +170,39 @@ RabbitMQ 如果丢失了数据,主要是因为你消费的时候,**刚消费

#### 消息丢失的场景

1. 生产者发送消息到MQ有可能丢失消息
2. MQ收到消息后写入硬盘可能丢失消息
1. 生产者发送消息到 MQ 有可能丢失消息
2. MQ 收到消息后写入硬盘可能丢失消息
3. 消息写入硬盘后,硬盘坏了丢失消息
4. 消费者消费MQ也可能丢失消息
5. 整个MQ节点挂了丢失消息
4. 消费者消费 MQ 也可能丢失消息
5. 整个 MQ 节点挂了丢失消息

#### 生产者发送消息时如何保证不丢失?

解决发送时消息丢失的问题可以采用RocketMQ自带的**事物消息**机制
解决发送时消息丢失的问题可以采用 RocketMQ 自带的**事物消息**机制

事物消息原理:首先生产者会发送一个**half消息**(对原始消息的封装),该消息对消费者不可见,MQ通过ACK机制返回消息接受状态, 生产者执行本地事务并且返回给MQ一个状态(Commit、RollBack等),如果是Commit的话MQ就会把消息给到下游, RollBack的话就会丢弃该消息,状态如果为UnKnow的话会过一段时间回查本地事务状态,默认回查15次,一直是UnKnow状态的话就会丢弃此消息
事物消息原理:首先生产者会发送一个**half 消息**(对原始消息的封装),该消息对消费者不可见,MQ 通过 ACK 机制返回消息接受状态, 生产者执行本地事务并且返回给 MQ 一个状态(Commit、RollBack 等),如果是 Commit 的话 MQ 就会把消息给到下游, RollBack 的话就会丢弃该消息,状态如果为 UnKnow 的话会过一段时间回查本地事务状态,默认回查 15 次,一直是 UnKnow 状态的话就会丢弃此消息

为什么先发一个half消息,作用就是先判断下MQ有没有问题,服务正不正常。
为什么先发一个 half 消息,作用就是先判断下 MQ 有没有问题,服务正不正常。

#### MQ收到消息后写入硬盘如何保证不丢失
#### MQ 收到消息后写入硬盘如何保证不丢失

数据存盘绕过缓存,改为同步刷盘,这一步需要修改Broker的配置文件,将flushDiskType改为SYNC_FLUSH同步刷盘策略,默认的是ASYNC_FLUSH异步刷盘,一旦同步刷盘返回成功,那么就一定保证消息已经持久化到磁盘中了。
数据存盘绕过缓存,改为同步刷盘,这一步需要修改 Broker 的配置文件,将 flushDiskType 改为 SYNC_FLUSH 同步刷盘策略,默认的是 ASYNC_FLUSH 异步刷盘,一旦同步刷盘返回成功,那么就一定保证消息已经持久化到磁盘中了。

#### 消息写入硬盘后,硬盘坏了如何保证不丢失?

为了保证磁盘损坏导致丢失数据,RocketMQ采用主从机构,集群部署,Leader中的数据在多个Follower中都存有备份,防止单点故障导致数据丢失。
为了保证磁盘损坏导致丢失数据,RocketMQ 采用主从机构,集群部署,Leader 中的数据在多个 Follower 中都存有备份,防止单点故障导致数据丢失。

Master节点挂了怎么办?Master节点挂了之后DLedger登场
- 接管MQ的commitLog
Master 节点挂了怎么办?Master 节点挂了之后 DLedger 登场

- 接管 MQ 的 commitLog
- 选举从节点
- 文件复制 uncommited状态 多半从节点收到之后改为commited
- 文件复制 uncommited 状态 多半从节点收到之后改为 commited

#### 消费者消费MQ如何保证不丢失
#### 消费者消费 MQ 如何保证不丢失

1. 如果是网络问题导致的消费失败可以进行重试机制,默认每条消息重试16次
2. 多线程异步消费失败,MQ认为已经消费成功但是实际上对于业务逻辑来说消息是没有落地的,解决方案就是按照mq官方推荐的先执行本地事务再返回成功状态
1. 如果是网络问题导致的消费失败可以进行重试机制,默认每条消息重试 16 次
2. 多线程异步消费失败,MQ 认为已经消费成功但是实际上对于业务逻辑来说消息是没有落地的,解决方案就是按照 mq 官方推荐的先执行本地事务再返回成功状态

#### 整个MQ节点挂了如何保证不丢失
#### 整个 MQ 节点挂了如何保证不丢失

这种极端情况可以消息发送失败之后先存入本地,例如放到缓存中,另外启动一个线程扫描缓存的消息去重试发送。