RocketMQ 的消息刷盘策略有哪些(同步刷盘与异步刷盘)?
在 RocketMQ 中,刷盘(Flush)指的是将 Broker 接收到的消息从内存(PageCache)持久化到物理磁盘(Disk)上的过程。刷盘策略直接决定了消息的可靠性和 Broker 的吞吐量/延迟。
RocketMQ 主要提供两种刷盘策略:同步刷盘(SYNC_FLUSH) 和 异步刷盘(ASYNC_FLUSH)。
以下是这两种策略的详细解析,以及它们在底层的实现原理对比:
1. 同步刷盘(SYNC_FLUSH)
工作原理:
当 Producer 发送一条消息到 Broker 时,Broker 会将消息写入系统的 PageCache,然后阻塞等待,强制系统将 PageCache 中的数据刷入物理磁盘。只有确认磁盘写入成功后,Broker 才会向 Producer 返回“发送成功”(ACK)的响应。
- 优点:
- 极高的可靠性:消息一旦返回发送成功,说明已经安全落在物理磁盘上。即使服务器突然断电或操作系统崩溃,消息也不会丢失。
- 缺点:
- 吞吐量低、延迟高:因为每次发消息都需要等待磁盘的 I/O 操作完成,磁盘的写入速度远低于内存,这成为性能瓶颈。
- 配置方式:
在broker.conf中设置:flushDiskType = SYNC_FLUSH - 适用场景:
金融交易、订单支付等对数据完整性要求极高,绝对不允许消息丢失的核心业务。
2. 异步刷盘(ASYNC_FLUSH)
工作原理:
当 Producer 发送一条消息到 Broker 时,Broker 将消息写入操作系统的 PageCache 后,立即向 Producer 返回“发送成功”(ACK),而不等待数据真正写到磁盘上。
与此同时,Broker 内部会有一个后台线程(FlushRealTimeService)以固定的频率(默认约 500ms)或者根据 PageCache 中积累的数据量,将内存中的数据批量刷入物理磁盘。
- 优点:
- 极高的吞吐量、极低的延迟:因为写操作仅仅是在内存(PageCache)中完成就返回了,几乎没有 I/O 阻塞。
- 缺点:
- 存在数据丢失风险:
- 如果只是 RocketMQ 的 JVM 进程崩溃,数据不会丢失(因为数据已经交给操作系统的 PageCache,OS 会负责将其刷入磁盘)。
- 如果是操作系统崩溃或者服务器突然断电,尚未从 PageCache 刷入物理磁盘的数据将会丢失。
- 存在数据丢失风险:
- 配置方式:
在broker.conf中设置:flushDiskType = ASYNC_FLUSH(这是 RocketMQ 的默认配置)。 - 适用场景:
日志收集、用户行为追踪、大并发量但对少量数据丢失有一定容忍度的业务场景。
3. 进阶:异步刷盘下的内存读写分离(TransientStorePool)
在异步刷盘(ASYNC_FLUSH)模式下,RocketMQ 还提供了一种高阶优化机制,称为 TransientStorePool(临时存储池),也就是常说的“读写分离”或“堆外内存异步提交”。
工作原理:
- 开启该机制后,消息写入时不再直接写 PageCache,而是先写到 RocketMQ 预先分配的堆外内存(DirectByteBuffer)中,然后立即返回 ACK 给 Producer。
- 有一个后台线程(
CommitRealTimeService)将堆外内存中的数据异步提交(Commit)到 FileChannel(即 PageCache)。 - 另一个后台线程(
FlushRealTimeService)再将 PageCache 中的数据异步刷盘(Flush)到物理磁盘。
- 为什么这么设计?
- 解决 PageCache 污染和锁竞争:在普通模式下,消息的读和写都在操作系统的 PageCache 中进行。当高并发或者读取历史消息时,会产生严重的 PageCache 竞争(Page Fault),导致写入延迟抖动。
- 读写分离:开启后,写操作走堆外内存,读操作走 PageCache,实现了内存级别的读写分离,极大保证了高并发写入时的稳定性。
- 数据丢失风险(最高):
如果 RocketMQ 进程(JVM)崩溃,由于数据还在堆外内存中没有进入操作系统的 PageCache,这部分数据也会丢失。 - 配置方式:
在broker.conf中设置:flushDiskType = ASYNC_FLUSHtransientStorePoolEnable = true(注意:此功能只有在异步刷盘模式下才生效,同步刷盘配置此项无效)。
4. 总结与对比表
| 特性 | 同步刷盘 (SYNC_FLUSH) | 异步刷盘 (ASYNC_FLUSH) | 异步刷盘 + 开启 TransientStorePool |
|---|---|---|---|
| 吞吐量 | 低 | 高 | 极高 |
| 响应延迟 | 高 (毫秒级) | 低 (微秒级) | 极低,且非常平稳 |
| 机器断电/OS宕机 | 不丢数据 | 丢失 PageCache 中的数据 | 丢失 堆外内存 + PageCache 的数据 |
| 进程(JVM)崩溃 | 不丢数据 | 不丢数据 | 丢失 堆外内存中的数据 |
| 读写冲突 | 存在 (都在 PageCache) | 存在 (都在 PageCache) | 无冲突 (写堆外内存,读 PageCache) |
5. 生产环境的最佳实践
在实际生产环境中,高可用和高可靠性不仅仅依赖于刷盘策略,还需要结合“主从复制策略”(Broker 角色)来综合考量。
企业中最常用的“高性价比”黄金组合是:
👉 同步复制(SYNC_MASTER) + 异步刷盘(ASYNC_FLUSH)
- 原理解释:Master 收到消息后,写到本地内存(不等待本地磁盘刷盘),然后通过网络将消息同步给 Slave。只有 Slave 也接收到消息后,才向 Producer 返回 ACK。
- 优势:由于网络同步速度通常快于磁盘同步写入速度,这种方式既保证了较高的吞吐量和低延迟,又保证了数据安全(只要 Master 和 Slave 不同时断电,数据就不会丢)。