38

探秘 RocketMQ 消息持久化机制

 4 years ago
source link: http://www.cnblogs.com/jamaler/p/12664576.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

我们知道 RocketMQ 是一款高性能、高可靠的分布式消息中间件,高性能和高可靠是很难兼得的。因为要保证高可靠,那么数据就必须持久化到磁盘上,将数据持久化到磁盘,那么可能就不能保证高性能了。

RocketMQ 在兼容这两方面做的不错,先从磁盘说起, 现代的磁盘都是高性能的,写速度并不一定比网络的数据传输速度慢 。比如 SSD 固态硬盘在 M.2 NVMe协议下,顺序写的速度可以达到 1500 MB/s,就算是普通磁盘,如果性能比较高的话,顺序写的速度可以达到 450MB/s~600MB/s。

在顺序写的情况下是这速度,但是不人为控制的话,磁盘采用的是随机写,在随机写的情况下,磁盘的写入速度急速下降, 磁盘的随机写速度可能只有几百KB/s,这远远要慢于网络传输速度,所以它并不能满足高性能的要求

RocketMQ 在持久化的设计上,采取的是 消息顺序写、随机读的策略 ,利用磁盘顺序写的速度,让磁盘的写速度不会成为系统的瓶颈。并且采用 MMPP 这种“零拷贝”技术,提高消息存盘和网络发送的速度。极力满足 RocketMQ 的高性能、高可靠要求。

上述从硬件的角度聊聊了高性能的保证,这些咱也不懂,还是来看看 RocketMQ 持久化机制的架构图吧。

VrYfY36.jpg!web

在 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)。

uqIFnqV.jpg!web

异步刷盘方式(默认):消息写入到内存的 PAGECACHE中,就立刻给客户端返回写操作成功,当 PAGECACHE 中的消息积累到一定的量时,触发一次写操作,将 PAGECACHE 中的消息写入到磁盘中。这种方式 吞吐量大,性能高,但是 PAGECACHE 中的数据可能丢失,不能保证数据绝对的安全

同步刷盘方式:消息写入内存的 PAGECACHE 后,立刻通知刷盘线程刷盘,然后等待刷盘完成,刷盘线程执行完成后唤醒等待的线程,返回消息写成功的状态。这种方式 可以保证数据绝对安全,但是吞吐量不大

关于RocketMQ 持久化机制的分享就这些,感谢您的阅读,希望这篇文章对您的学习或者工作有一点帮助。 有收获的话,也可以帮忙推荐给其他的小伙伴,让更多的人受益,万分感谢

欢迎关注公众号【 互联网平头哥 】。这里有职场感悟、Java 技术,虽然不高大上,但通俗易懂。今天最好的是明天最低的要求,愿你我共同进步。

ri2e6zA.jpg!web


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK