RocketMQ消息存储及NameServer特性

RocketMQ采用文件系统存储消息,利用MappedByteBuffer实现零拷贝提高性能。存储结构包括CommitLog(存储消息内容)和ConsumerQueue(存储位置信息)。刷盘机制有同步和异步两种。消息堆积后不会立即删除,定期清理过期消息。NameServer作为路由注册中心,负责Broker的动态注册、心跳检测和路由信息管理,且NameServer实例间不通信,数据可能存在不一致。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

消息存储

存储方式

      RocketMQ 使用文件系统持久化消息。性能要比使用DB产品要高。文件顺序读写的速度大概是3G左右。

      RocketMQ在消息存储时使用了数据零拷贝技术来发送数据文件数据。

      MappedByteBuffer 内存映射

  • MappedByteBuffer使用虚拟内存,因此分配(map)的内存大小不受JVM的-Xmx参数限制(map方法中size的类型是long,long的最大值换算得MappedByteBuffer的最大值是2G)
  • 当文件超出1.5G限制时,可以通过position参数重新map文件后面的内容
  • MappedByteBuffer在处理大文件时的确性能很高,但也存在一些问题,如内存占用、文件关闭不确定,被其打开的文件只有在垃圾回收的才会被关闭,且这个时间点不确定

      为了使用零拷贝技术,RocketMQ的文件存储大小默认每个1G,超过1G会重新建立一个新文件


存储结构

      CommitLog:
      存储消息的详细内容,按照消息收到的顺序,所有消息都存储在一起。每个消息存储后都会有一个offset,代表在commitLog中的偏移量。
      默认配置是MessageStoreConfig 核心方法为 putMessage 写入消息

      CommitLog内部结构
      MappedFileQueue -> MappedFile MappedFile默认大小为1G

      ConsumerQueue
      通过消息偏移量建立的消息索引。
      针对每个Topic创建,消费逻辑队列,存储位置信息,用来快速定位CommitLog中的数据位置。
      启动后会被加载到内存中,加快查找消息速度。
      以Topic作为文件名称,每个Topic下又以queue id作为文件夹分组。
      默认大小为48M

      indexFile
      消息的Key和时间戳索引,默认存储路径为/root/store/


刷盘机制

      同步刷盘:
      消息被Broker写入磁盘后再给producer响应

      异步刷盘:
      消息被Broker写入内存后立即给producer响应,当内存中消息堆积到一定程度的时候写入磁盘持久化

      每间隔10ms,执行一次数据持久化操作。

      写入消息时,避免消息分割到两个MapedFile中做了以下处理:

// Determines whether there is sufficient free space
            if ((msgLen + END_FILE_MIN_BLANK_LENGTH) > maxBlank) {
                this.resetByteBuffer(this.msgStoreItemMemory, maxBlank);
                // 1 TOTALSIZE
                this.msgStoreItemMemory.putInt(maxBlank);
                // 2 MAGICCODE
                不够放下一个消息的时候,用魔术字符代替
                this.msgStoreItemMemory.putInt(CommitLog.BLANK_MAGIC_CODE);
                // 3 The remaining space may be any value
                // Here the length of the specially set maxBlank
                final long beginTimeMills = CommitLog.this.defaultMessageStore.now();
                byteBuffer.put(this.msgStoreItemMemory.array(), 0, maxBlank);
                return new AppendMessageResult(AppendMessageStatus.END_OF_FILE, wroteOffset, maxBlank, msgId, msgInner.getStoreTimestamp(),
                    queueOffset, CommitLog.this.defaultMessageStore.now() - beginTimeMills);
            }

消息堆积

      消息被消费后不会立即删除,每条消息都会持久化到CommitLog中,每个consumer连接到broker后会维持消费进度信息,当有消息消费后只是当前consumer的消费进度(CommitLog的offset)更新了。
      清理过期消息:默认48小时后会删除不再使用的CommitLog文件,删除时先检查这个文件最后访问时间,再判断是否大于过期时间,然后在指定时间删除(默认是凌晨4点)。


NameServer特性

功能

      NameServer是一个非常简单的Topic路由注册中心,其角色类似Dubbo中的zookeeper,支持Broker的动态注册与发现。

  • Broker管理,NameServer接受Broker集群的注册信息并且保存下来作为路由信息的基本数据。然后提供心跳检测机制,检查Broker是否还存活;
  • 路由信息管理,每个NameServer将保存关于Broker集群的整个路由信息和用于客户端查询的队列信息。然后Producer和Conumser通过NameServer就可以知道整个Broker集群的路由信息,从而进行消息的投递和消费

特性

  • NameServer通常也是集群的方式部署,各实例间相互不进行信息通讯。Broker是向每一台NameServer注册自己的路由信息,所以每一个NameServer实例上面都保存一份完整的路由信息。当某个NameServer因某种原因下线了,Broker仍然可以向其它NameServer同步其路由信息,Producer,Consumer仍然可以动态感知Broker的路由的信息。
  • NameServer实例时间互不通信,这本身也是其设计亮点之一,即允许不同NameServer之间数据不同步(像Zookeeper那样保证各节点数据强一致性会带来额外的性能消耗)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值