RocketMQ之消息刷盘和读取

    上篇我介绍了RocketMQ消息存储结构,那Producer是怎么把消息存到文件中,Consumer怎么读取数据呢?

Producer消息刷盘

消息在通过Producer写入RocketMQ的时候,有两种写磁盘方式,分布式同步刷盘和异步刷盘。
RocketMQ之消息刷盘和读取
1、同步刷盘(更安全,不会丢消息)
在返回写成功状态时,消息已经被写入磁盘。具体流程是:

  • 消息从socket 进入java 堆
  • 消息写入PAGECACHE物理内存中,
  • 通知刷盘线程刷盘, 然后等待刷盘完成
  • 刷盘线程执行完成后唤醒等待的线程
  • 返回消息写成功的状态给Producer

2、异步刷盘(性能更好)
同步和异步的唯一区别是同步刷盘需要等待刷盘完成才返回,而异步刷盘写完 PAGECACHE 直接返回。异步刷盘流程是:

  • 消息从socket 进入java 堆
  • 消息写入PAGECACHE物理内存中,
  • 返回消息写成功的状态给Producer,然后等待刷盘完成
  • 当内存里的消息量积累到一定程度时,统一触发写磁盘动作,把消息刷到磁盘文件中

    在返回写成功状态时,消息可能只是被写入了内存的PAGECACHE,写操作的返回快,吞吐量大;当内存里的消息量积累到一定程度时,统一触发写磁盘动作,快速写入。当然,RocketMQ为了提高性能,会尽可能地保证磁盘的顺序写。

    使用同步刷盘还是异步刷盘,都是通过Broker配置文件里的flushDiskType 参数设置的,这个参数被配置成SYNC_FLUSH、ASYNC_FLUSH中的 一个。

Consumer消息读取

RocketMQ 的所有消息都是持久化的, 先写入系统 PAGECACHE, 然后刷盘, 可以保证内存与磁盘都有一份数据,访问时,直接从内存读取。Consumer读取消息时,尽量从内存中读取,速度更快。
RocketMQ之消息刷盘和读取

  • Consumer 拉消息(正常消费),消息直接从PAGECACHE(消息在物理内存)转入socket到达Consumer,不经过java 堆。这种消费场景最多,线上96G 物理内存,按照1K 消息算,可以在物理内存缓存1亿条消息。
  • Consumer 拉消息(异常消费),消息直接从PAGECACHE(消息在虚拟内存)转入socket转入socket到达Consumer,不经过java 堆。
  • Consumer 拉消息(异常消费),由于socket 访问了虚拟内存,产生缺页中断,此时会产生磁盘IO,从磁盘Load 消息到PAGECACHE,然后直接从socket 发出去到达Consumer