RocketMQ高性能设计之数据存储设计
RocketMQ高性能设计之数据存储设计
数据存储设计
数据存储的核心由两部分组成:CommitLog数据存储文件和ConsumeQueue消费队列文件。
Producer将消息发送到Broker服务器,Broker会把所有消息都存储在CommitLog文件中,再由CommitLog转发到ConsumeQueue文件提供给各个Consumer消费。
顺序写盘
顺序写盘指写磁盘上的文件采用顺序写的方式。一次磁盘请求完成过程由三个动作组成:寻道、旋转延迟、数据传输。
- 寻道:磁头移动定位到指定磁道,时间很长
- 旋转延迟:等待指定扇区旋转到磁头下,机械硬盘和每分钟多少转有关系,时间很短。
- 数据传输:数据通过系统总线从磁盘传送到内存,时间很短
磁盘读写最慢的动作是寻道,顺序写几乎不用换磁道
CommitLog文件负责存储消息数据的文件,所有Topic的消息会先存在{ROCKETMQ_HOME}/store/commitlog文件夹下的文件中,消息数据写入CommitLog文件是加锁串行追加写入。
RocketMQ为了保证消息发送的高吞吐量,使用单个文件存储所有Topic的消息,从而保证消息存储是磁盘顺序写
CommitLog默认1GB,写满1GB再写新的文件,文件名安装该文件的起始字节偏移量offset命名,20位数字,这样设计的目的是在消费消息时能够根据偏移量offset快速定位到消息存储在某个CommitLog文件中,加快消息的检索速度
消费队列设计
ConsumeQueue负责存储消费队列文件,在消息写入CommitLog文件时,会异步转发到ConsumeQueue文件,然后提供给Consumer消费。ConsumeQueue文件并不存储具体的消息数据,只存CommitLog的偏移量offset、消息大小size、消息Tag HashCode
每个Topic在某个Broker下对应多个队列Queue,默认是4个消费队列Queue。每条记录的大小是20B,默认一个文件存储30万个记录,文件名同样按照字节偏移量offset命名,文件名固定长度为20位。
集群模式下,Broker记录客户端对每个消费队列的消费偏移量,定位到ConsumeQueue里相应的记录,并通过CommitLog的offset定位到CommitLog文件里的该条消息
消息跳跃读
RocketMQ读取消息依赖操作系统的PageCache,PacheCache命中率越高则读性能越高,操作系统会尽量预读数据,使应用直接访问磁盘的概率降低
消息队列文件的读取流程:
- 检查要读的数据是否在上次预读的Cache中
- 如果没有命中Cache,操作系统从磁盘中读取对应的数据页,并将该数据页之后的连续几页一起读入Cache中,再将应用需要的数据返回给应用,这种方式叫跳跃读取
- 如果命中Cache,上次缓存的数据有效,操作系统认为在顺序读盘,则继续扩大缓存数据范围,将之前缓存的数据页之后的几页数据再读取到Cache中
CPU RAM DISK速度不相同,按速度高低排列为CPU>RAM>DISK,CPU与RAM之间使用CPUCache提高访问速度,RAM与磁盘之间使用PageCache提供系统对文件的访问速度
数据零拷贝
一般写文件数据要从用户态拷贝到内核态,再由内核态写入物理文件。所谓零拷贝,指的是用户态与内核态之间不存在拷贝。
RocketMQ中的文件读写主要通过Java NIO的MappedByteBuffer来进行文件映射。利用JavaNIO中的FileChannel模型,可以直接将物理文件映射到缓冲区的PageCache,少了一次数据拷贝过程,提高了读写速度。
总结
这篇文章主要讲了RocketMQ高性能设计的数据存储设计的部分,它的数据库设计的特点有顺序写盘,消息跳跃读,数据零拷贝等等高性能的特点,这也是RocketMQ中值得我们学习和关注的知识点。
参考文献
RocketMQ文档:
https://github.com/apache/rocketmq/blob/master/docs/cn/design.md
- 点赞
- 收藏
- 关注作者
评论(0)