在RocketMQ中,消息存储是由CommitLog和ConsumerQueue配合完成

消息存储结构

首先我们先来看下整体的消息存储结构
在这里插入图片描述

基本过程:

  1. 生产者在生产消息的时候是将消息存储在CommitLog文件中
  2. 消费者在读取消息时,先读取 ConsumeQueue,然后再通过ConsumeQueue中的位置信息读取CommitLog文件中具体的消息数据得到原始消息

这里有两个需要注意的地方,CommitLogConsumeQueue结构

CommitLog

可以理解这个其实就是一个日志文件,该文件默认最大为1GB,超过1GB后会轮到下一个CommitLog文件进行存储。通过CommitLog,RocketMQ将所有消息都进行顺序存储,充分利用了磁盘顺序写提高数据存储性能

在这里插入图片描述

  • 4字节表示消息的长度,消息的长度是整个消息体所占用的字节数的大小
  • 4字节的魔数,是固定值,有MESSAGE_MAGIC_CODE和BLANK_MAGIC_CODE
  • 4字节的CRC,是消息体的校验码,用于防止网络、硬件等故障导致数据与发送时不一样带来的问题 - 4字节的queueId,表示消息发到了哪个MessageQueue(逻辑上相当于kakka的partition)
  • 4字节的flag,flag是创建Message对象时由生产者通过构造器设定的flag值
  • 8字节的queueOffset,表示在queue中的偏移量
  • 8字节的physicalPosition,表示在存储文件中的偏移量
  • 4字节sysFlag,是生产者相关的信息标识,具体生产逻辑可以看相关代码
  • 8字节消息创建时间
  • 8字节消息生产者的host
  • 8字节消息存储时间
  • 8字节消息存储的机器的host
  • 4字节表示重复消费次数
  • 8字节消息事务相关偏移量
  • 4字节表示消息体的长度消息休,不是固定长度,和前面的4字节的消息体长度值相等
  • 1字节表示topic的长度,因此topc的长度最多不能超过127个字节,超过的话存储会出错(有前置校验)
  • Topic,存储topic,因为topic不是固定长度,所以这里所占的字节是不固定的,和前一个表示topic长度的字节的值相等
  • 2字节properties的长度,properties是创建消息时添加到消息中的,因此,添加在消息中的poperties不能太多太大,所有的properties的kv对在拼接成string后,所占的字节数不能超过2^15-1
  • Properties的内容,也不是固定长度,和前面的2字节properties长度的值相同

ConsumeQueue

在这里插入图片描述

  • Offset:表示在默认1GB的CommitLog文件中的偏移量(位置)
  • Size:表示消息占用的长度
  • tagCode:消息所属的tag的hash值

可以看到一个消息的数据包占用共20个字节,RocketMQ在消息存储上并没有存储具体的消息,而是将具体消息数据存储在CommitLog文件中,这也是和Kafka很大的一个不同点(Kafka中是存储具体消息数据的)在这里插入图片描述

总结

RocketMQ这样的消息存储结构它的优势是什么,接下来我们通过与Kafka对比来看下

  1. 写顺序不同:RocketMQ 将所有消息存储在同一个CommitLog中,使得RocketMQ中的消息是磁盘顺序写,顺序IO可以接近内存的速度。而Kafka中在消息存储上是随机IO,随机IO要比顺序IO慢得多
  2. 消息数据存储方式不同:RocketMQ中每个消息仅存储20字节的消息位置信息(原始数据存在CommitLog),而Kafka将每个partition的消息分开存储,因此在单个Broker中RocketMQ能支持更多的topic、partition
  3. 消息数据大小不同:在RocketMQ中,ConsumeQueue也是随机IO,但确能比Kafka支持更多的partition,原因是RocketMQ通过MappedFile的方式读写ConsumeQueue,操作系统对内存映射文件有page cache,且一个消息位置数据仅有20字节,一个page中可以包含很多的消息数据,相当于直接对内存随机IO,所以效率要比Kafka高出得多
Logo

Kafka开源项目指南提供详尽教程,助开发者掌握其架构、配置和使用,实现高效数据流管理和实时处理。它高性能、可扩展,适合日志收集和实时数据处理,通过持久化保障数据安全,是企业大数据生态系统的核心。

更多推荐