RocketMQ之消息的存储

1、MQ消息消息存储的选择

1.1、消息存储方式

主要分为以下几种:

  • 分布式KV存储: 比如ActiveMQ中采用的levelDB、Redis, 这种存储方式对于消息读写能力要求不高的情况下可以使用

  • 文件存储系统: 常见的比如kafka、RocketMQ、RabbitMQ都是采用消息刷盘到所部署的机器上的文件系统来做持久化,这种方案适合对于有高吞吐量要求的消息中间件,因为消息刷盘是一种高效率,高可靠、高性能的持久化方式,除非磁盘出现故障,否则一般是不会出现无法持久化的问题

  • 关系型数据库: 比如ActiveMQ可以采用mysql作为消息存储,关系型数据库在单表数据量达到千万级的情况下IO性能会出现瓶颈,所以ActiveMQ并不适合于高吞吐量的消息队列场景。

总的来说,对于存储效率,文件系统要优于分布式KV存储,分布式KV存储要优于关系型数据库

1.2、RocketMQ选择文件存储系统方式

RocketMQ作为一款高性能高可靠的消息中间件,高可靠那就要求对消息进行持久化,就要写入磁盘,而高性能又与其矛盾,那么RocketMQ是如何做到的呢?

通过消息顺序写随机读的策略,实际上磁盘顺序写是非常快的。

2、RocketMQ存储结构

2.1、存储文件介绍

默认存储路径为:/root/store


介绍下各个文件:

  • commitlog: 消息真正的物理存储文件,所有消息都存储在CommitLog文件中。每个broker上的commitlog为当前机器上的所有consumerQueue共享,不做任何分区。

    commitLog中文件默认大小为1G,可以动态配置。当一个文件写满后,会生成一个新的,所有topic数据是顺序写入在commitLog文件中的。文件名长度为20位,左边补0,剩余为起始偏移量,比如00000000000000000000为第一个文件,00000000001073741824是第二个文件,1073741824是起始偏移量。

  • consumequeue: 表示消息消费的逻辑队列,类似于数据库的索引文件。里面包含MessageQueue在commitlog中的物理位置偏移量offset,消息内容的大小和Message Tag的hash值。对于实际物理存储来说,consumeQueue对应每个topic和queueId下的文件,每个文件默认大小约为600w个子节,如果文件满后会生成新的文件。



为什么要consumequeue?

CommitLog文件是存放消息数据的地方,所有的消息都将存入到CommitLog文件中。生产者将消息发送到 RocketMQ的Broker后,Broker服务器会将消息顺序写入到CommitLog文件中,这也就是RocketMQ高性能的原因,因为我们知道磁盘顺序写特别快,RocketMQ 充分利用了这一点,极大的提高消息写入效率。但是消费者消费消息的时候,可能就会遇到麻烦,每一个消费者只能订阅一个主题,消费者关心的是订阅主题下的所有消息,但是同一主题的消息在CommitLog文件中可能是不连续的,那么消费者消费消息的时候,需要将 CommitLog文件加载到内存中遍历查找订阅主题下的消息,频繁的IO操作,性能就会急速下降。为了解决这个问题,RocketMQ 引入了Consumequeue文件。Consumequeue文件可以看作是索引文件,类似MySQL 中的二级索引。在存放了同一主题下的所有消息,消费者消费的时候只需要去对应的Consumequeue组中取消息即可。Consumequeue文件不会存储消息的全量信息,了解MySQL索引的话,应该好理解这里。

  • index: 是RocketMQ为消息订阅构建的索引文件,用来提高根据主题与消息队列检索消息的速度。
  • abort: broker在启动的时候会创建一个空的abort文件,在shutdown时候删除,用于标识进程是否正常退出,如果不是,会在启动时做故障恢复。

3、存储流程描述

3.1、发送消息,写入commitlog

producer将消息发送到broker后,broker会采用同步或者异步的方式将消息写入到commitlog中去,为保证消息存储不混乱,写log之前会加锁,同时能够使消息顺序写入到commitlog中去,这里是顺序io,所以速度会非常快。

3.2、写入consumerqueue

commitlog持久化消息之后,会把里面的消息dispatch到对应的consumequeue上。

3.3、消费消息

消息消费时候,会先读取consumerqueue,会拿到消息在commitlog中的物理偏移量offset等信息。

直接从consumerqueue中读取的消息是没有数据的,真正的消息在commitlog中,所以还要从commitlog中去读取消息。

4、聊聊数据刷盘

因为操作系统PageCache的存在,PageCache是OS对文件的缓存,用于加速对文件的读写,所以一般都是先写入到PageCache中,然后再持久化到磁盘上。我们熟悉的其他组件,MySQL、Redis 等都是如此,RocketMQ 也不列外。在 RocketMQ中提供了同步刷盘异步刷盘两种刷盘方式,可以通过broker.conf配置中的flushDiskType参数来设置(SYNC_FLUSHASYNC_FLUSH)。

  • 异步刷盘方式(默认):消息写入到内存的PageCache中,就立刻给客户端返回写操作成功,当PageCache中的消息积累到一定的量时,触发一次写操作,将PageCache中的消息写入到磁盘中。这种方式吞吐量大,性能高,但是PageCache中的数据可能丢失,不能保证数据绝对的安全。
  • 同步刷盘方式:消息写入内存的PageCache后,立刻通知刷盘线程刷盘,然后等待刷盘完成,刷盘线程执行完成后唤醒等待的线程,返回消息写成功的状态。这种方式可以保证数据绝对安全,但是吞吐量不大。

5、清除存储文件时机

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值