RocketMQ学习(六):消息存储深入

目录

消息存储

存储介质

消息的存储与发送的性能保障

消息存储结构

刷盘机制


消息存储

为了保证RocketMQ的高可靠性要求,MQ会对消息进行持久化

  1. 生产者发送消息
  2. MQ收到消息后,对消息进行持久化,在储存中新增一条记录
  3. 返回ACK给生产者
  4. MQ推送消息给对应的消费者,然后等待消费者返回ACK
  5. 如果消费者返回了ACK,则MQ执行消息删除的操作,若超时未返回,MQ会认为消费失败重新推送消息,重复执行4,5,6步骤
  6. MQ删除消息

存储介质

  • 关系型数据库

        例如Apache的ActiveMQ就可以通过JDBC来进行消息的持久化,设置一些XML的配置信息即可。但是,普通的关系型数据库,如MySQL,在数据量达到千万级别后会造成IO的性能瓶颈。在可靠性方面,这种方式非常依赖于数据库的性能,一旦数据库宕机,就会导致消息无法存储的线上故障。

  • 文件系统

        目前业界较为常用的几款产品(RocketMQ/Kafka/RabbitMQ)均采用的是消息刷盘至所部署虚拟机/物理机的文件系统来做持久化(刷盘一般可以分为异步刷盘和同步刷盘两种模式)。消息刷盘为消息存储提供了一种高效率、高可靠性和高性能的数据持久化方式。除非部署MQ机器本身或是本地磁盘挂了,否则一般是不会出现无法持久化的故障问题。

所以在性能上:文件系统>关系型数据库

消息的存储与发送的性能保障

  • 消息存储

        我们知道,消息多是通过网络发送过来的,RocketMQ如何保证消息存储的速度匹配上网络传输速度呢。其实以目前大多数SATA3接口的SSD顺序写的速度能达到600MB/s(更不说M.2接口了),但随机写差不多只有100KB/s,相差了6000倍。所以RocketMQ在存储消息时采用顺序写的方式来保证效率。

  • 消息发送(指MQ)

        一台MQ服务器把本地消息发送至客户端分两步

  1. 从本地读取消息;
  2. 将读取的内容通过网络发送出去。

        因linux系统分为【用户态】和【内核态】,文件操作、网络操作需要涉及这两种形态的切换,免不了进行数据复制。

        看似只有两步,实际在系统内部进行了四次数据的复制,如果数据非常大的话,4次复制会导致读的速度非常慢。

  1. 从磁盘复制数据到内核态内存;
  2. 从内核态内存复制到用户态内存(也就是应用程序独占的内存);
  3. 然后从用户态内存复制到网络驱动的内核态内存;
  4. 最后是从网络驱动的内核态内存复 制到网卡中进行传输。

        那么RocketMQ是如何提高读的效率的呢,它是利用了Java中的MappedByteBuffer来实现一个叫做“零拷贝”的技术,通过省去数据向用户态内存的复制,来提高读取速度。

消息存储结构

在之前的博客中,我们在搭建集群的配置里设置了一些关系消息存储的路径。

#存储路径
storePathRootDir=/opt/rocketmq/store-m
#commitLog 存储路径
storePathCommitLog=/opt/rocketmq/store-m/commitlog
#消费队列存储路径存储路径
storePathConsumeQueue=/opt/rocketmq/store-m/consumequeue
#消息索引存储路径
storePathIndex=/opt/rocketmq/store-m/index
#checkpoint 文件存储路径
storeCheckpoint=/opt/rocketmq/store-m/checkpoint
#abort 文件存储路径
abortFile=/opt/rocketmq/store-m/abort

对应系统中

        RocketMQ消息的存储是由ConsumeQueue和CommitLog配合完成的,消息真正的物理存储文件是CommitLog,ConsumeQueue是消息的逻辑队列,类似数据库的索引文件,存储的是指向物理存储的地址。每 个Topic下的每个Message Queue都有一个对应的ConsumeQueue文件。

CommitLog:存储消息的元数据,发送的消息的所有信息(Topic,QueueId,Message)都会存到这里面

        我们可以看到,查看CommitLog,里面就有一个大小为1G,用于存储消息的文件(当前只有一个,消息多了会自动创建新的,大小也是1G)。

        这是因为前面提到的,RocketMQ使用MappedByteBuffer这种内存映射的方式有几个限制,其中之一是一次只能映射1.5~2G 的文件至用户态的虚拟内存,所以每一个文件的大小是1G(小于2G即可)。

ConsumerQueue:存储的是CommitLog里每个消息的索引,为的是提升消息读取的效率

        ConsumerQueue里面存了消息最小的偏移量,已经消费的偏移量,最大的偏移量,且丢失后能通过CommitLog还原。

        可以看到每一个Topic都有四个消息队列(0,1,2,3),每一个消息队列会对应一个ConsumerQueue。其和CommitLog里的文件同名,大小不大。也就意味着Linux能够将其加载到内存中读取,进一步加快读消息的速度。

IndexFile:也是索引文件,与ConsumerQueue通过偏移量查找不同,IndexFile提供了通过时间区间来查,key来查的方式

刷盘机制

  • 同步刷盘

        在返回写成功状态时,消息已经被写入磁盘。具体流程是,消息写入内存的PAGECACHE后,立刻通知刷盘线程刷盘, 然后等待刷盘完成,刷盘线程执行完成后唤醒等待的线程,返回消息写成功的状态。

  • 异步刷盘

        在返回写成功状态时,消息可能只是被写入了内存的PAGECACHE,写操作的返回快,吞吐量大;当内存里的消息量积累到一定程度时,统一触发写磁盘动作,快速写入。

  • 配置
#刷盘方式
#- ASYNC_FLUSH 异步刷盘
#- SYNC_FLUSH 同步刷盘
flushDiskType=SYNC_FLUSH

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值