我们知道 RocketMQ 是一款高性能、高可靠的分布式消息中间件,高性能和高可靠是很难兼得的。因为要保证高可靠,那么数据就必须持久化到磁盘上,将数据持久化到磁盘,那么可能就不能保证高性能了。
RocketMQ 在兼容这两方面做的不错,先从磁盘说起,现代的磁盘都是高性能的,写速度并不一定比网络的数据传输速度慢。比如 SSD 固态硬盘在 M.2 NVMe协议下,顺序写的速度可以达到 1500 MB/s,就算是普通磁盘,如果性能比较高的话,顺序写的速度可以达到 450MB/s~600MB/s。
在顺序写的情况下是这速度,但是不认为控制的话,磁盘采用的是随机写,在随机写的情况下,磁盘的写入速度急速下降,磁盘的随机写速度可能只有几百KB/s,这远远要慢于网络传输速度,所以它并不能满足高性能的要求。
RocketMQ 在持久化的设计上,采取的是消息顺序写、随机读的策略,利用磁盘顺序写的速度,让磁盘的写速度不会成为系统的瓶颈。并且采用 MMPP 这种“零拷贝”技术,提高消息存盘和网络发送的速度。极力满足 RocketMQ 的高性能、高可靠要求。
上述从硬件的角度聊聊了高性能的保证,这些咱也不懂,还是来看看 RocketMQ 持久化机制的架构图吧。
在 RocketMQ 持久化机制中,涉及到了三个角色:
- CommitLog:消息真正的存储文件,所有消息都存储在 CommitLog 文件中。
- ConsumeQueue:消息消费逻辑队列,类似数据库的索引文件。
- IndexFile:消息索引文件,主要存储消息 Key 与 offset 对应关系,提升消息检索速度。
咱们逐一聊聊吧,CommitLog 文件是存放消息数据的地方,所有的消息都将存入到 CommitLog 文件中。生产者将消息发送到 RocketMQ 的 Broker 后,Broker 服务器会将消息顺序写入到 CommitLog 文件中,这也就是 RocketMQ 高性能的原因,因为我们知道磁盘顺序写特别快,RocketMQ 充分利用了这一点,极大的提高消息写入效率。
但是消费者消费消息的时候,可能就会遇到麻烦,每一个消费者只能订阅一个主题,消费者关心的是订阅主题下的所有消息,但是同一主题的消息在 CommitLog 文件中可能是不连续的,那么消费者消费消息的时候,需要将 CommitLog 文件加载到内存中遍历查找订阅主题下的消息,频繁的 IO 操作,性能就会急速下降。
为了解决这个问题,RocketMQ 引入了 Consumequeue 文件。Consumequeue 文件可以看作是索引文件,类似于 MySQL 中的二级索引。在存放了同一主题下的所有消息,消费者消费的时候只需要去对应的 Consumequeue 组中取消息即可。Consumequeue 文件不会存储消息的全量信息,了解 MySQL 索引的话,应该好理解这里,具体存储的字段,我在上图已经标注。这样做可以带来以下两个好处:
- 由于 Consumequeue 文件内容小,可以尽可能的保证 Consumequeue 文件全部读入到内存,提高消费效率。
- Consumequeue 文件也是会持久化的,不存全量信息可以节约磁盘空间。
IndexFile 是 RocketMQ 为消息订阅构建的索引文件,用来提高根据主题与消息队列检索消息的速度,这个就不细说了。
RocketMQ 持久化机制原理差不多就这些了,接下来聊一聊消息数据刷盘吧。
因为操作系统 PAGECACHE 的存在,PageCache是OS对文件的缓存,用于加速对文件的读写,所以一般都是先写入到 PAGECACHE 中,然后再持久化到磁盘上。我们熟悉的其他组件,MySQL、Redis 等都是如此。RocketMQ 也不列外。
在 RocketMQ 中提供了同步刷盘和异步刷盘两种刷盘方式,可以通过 Broker 配置文中中的 flushDiskType 参数来设置(SYNC_FLUSH、ASYNC_FLUSH)。
异步刷盘方式(默认):消息写入到内存的 PAGECACHE中,就立刻给客户端返回写操作成功,当 PAGECACHE 中的消息积累到一定的量时,触发一次写操作,将 PAGECACHE 中的消息写入到磁盘中。这种方式吞吐量大,性能高,但是 PAGECACHE 中的数据可能丢失,不能保证数据绝对的安全。
同步刷盘方式:消息写入内存的 PAGECACHE 后,立刻通知刷盘线程刷盘,然后等待刷盘完成,刷盘线程执行完成后唤醒等待的线程,返回消息写成功的状态。这种方式可以保证数据绝对安全,但是吞吐量不大。
关于RocketMQ 持久化机制的分享就这些,感谢您的阅读,希望这篇文章对您的学习或者工作有一点帮助。有收获的话,也可以帮忙推荐给其他的小伙伴,让更多的人受益,万分感谢。
最后
目前互联网上很多大佬都有 RocketMQ 相关文章,如有雷同,请多多包涵了。原创不易,码字不易,还希望大家多多支持。若文中有所错误之处,还望提出,谢谢。
作者:平头哥