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
版权声明: 本文为 InfoQ 作者【周杰伦本人】的原创文章。
原文链接:【http://xie.infoq.cn/article/07ecbd806638ed7c61e7b97d6】。文章转载请联系作者。
评论