目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

Offset、CommitLog、ZeroCopy

消息偏移量 Offset

  • 一个 Topic 下面有多个 message queue,message queue 是无限长的数组,一条消息进来下标就会涨 1,下标就是 offset(索引的位置),消息在某个 MessageQueue 里的位置,通过 offset 的值可以定位到这条消息,或者指示 Consumer 从这条消息开始向后处理。
  • message queue 中的 maxOffset 表示消息的最大 offset, maxOffset 并不是最新的那条消息的 offset,而是最新消息的 offset+1,minOffset 则是现存在的最小 offset。 fileReserveTime=48 默认消息存储 48 小时后,消息会被物理地从磁盘删除,message queue 的 min offset 也就对应增长。(1-5000,消息删除之后,1001-5000)所以比 minOffset 还要小的那些消息已经不在 broker 上了,就无法被消费。

Offset 的存储类型

  • 本地文件类型DefaultMQPushConsumer 的 BROADCASTING 模式,各个 Consumer 没有互相干扰,使用 LoclaFileOffsetStore,把 Offset 存储在本地。
  • Broker 代存储类型DefaultMQPushConsumer 的 CLUSTERING 模式,由 Broker 端存储和控制 Offset 的值,使用 RemoteBrokerOffsetStore。

Offset 的作用
 建议采用 pushConsumer,RocketMQ 自动维护 OffsetStore,如果用另外一种 pullConsumer 需要自己进行维护 OffsetStore。

  • 主要是记录消息的偏移量,有多个消费者进行消费
  • 集群模式下采用 RemoteBrokerOffsetStore, broker 控制 offset 的值
  • 广播模式下采用 LocalFileOffsetStore, 消费端存储

消息存储 CommitLog

消息存储是由 ConsumeQueue 和 CommitLog 配合完成

  • ConsumeQueue: 是逻辑队列, CommitLog 是真正存储消息文件的,存储的是指向物理存储的地址,Topic 下的每个 message queue 都有对应的 ConsumeQueue 文件,内容也会被持久化到磁盘
默认地址:store/consumequeue/{topicName}/{queueid}/fileName
/root/store/consumequeue/soulboy_pay_test_topic2/1

* Consume Queue存储使用hashcode定长,节约空间 
* 使用hashcode过滤可以不访问commit log(日志文件,真正存储消息的文件),可以高效过滤 
* 如果存在hash冲突,Consumer端可以进行再次确认(防止hash碰撞)
  • 什么是 CommitLog:消息文件的存储地址,
    生成规则
      每个文件的默认 1G =1024 * 1024 * 1024,commitlog 的文件名 fileName,名字长度为 20 位,左边补零,剩余为起始偏移量;比如 00000000000000000000 代表了第一个文件,起始偏移量为 0,文件大小为 1G=1 073 741 824Byte;当这个文件满了,第二个文件名字为 00000000001073741824,起始偏移量为 1073741824, 消息存储的时候会顺序写入文件,当文件满了则写入下一个文件。
/root/store/commitlog

判断消息存储在哪个 CommitLog 上
  例如 1073742827 为物理偏移量,则其对应的相对偏移量为 1003 = 1073742827 - 1073741824,并且该偏移量位于第二个 CommitLog。

概念梳理

Broker里面的一个Topic
	里面有多个MesssageQueue
		每个MessageQueue对应一个ConsumeQueue
			ConsumeQueue里面记录的是消息在CommitLog里面的物理存储地址

高性能之 ZeroCopy 零拷贝技术

高效原因

  • CommitLog 顺序写(偏移量), 存储了 MessagBody、message key、tag 等信息
  • ConsumeQueue 随机读(索引) + 操作系统的 PageCache + 零拷贝技术 ZeroCopy

传统数据发送技术
传统数据发送技术

 例子:将一个 File 读取并发送出去(Linux 有两个上下文,内核态,用户态)。File 文件的经历了 4 次 copy。

  1. 调用 read,将文件拷贝到了 kernel 内核态
  2. CPU 控制 kernel 态的数据 copy 到用户态
  3. 调用 write 时,user 态下的内容会 copy 到内核态的 socket 的 buffer 中
  4. 最后将内核态 socket buffer 的数据 copy 到网卡设备中传送

 缺点:增加了上下文切换、浪费了 2 次无效拷贝(即步骤 2 和 3)

read(file, tmp_buf, len);
write(socket, tmp_buf, len);

零拷贝技术
零拷贝技术
 请求 kernel 直接把 disk 的 data 传输给 socket,而不是通过应用程序传输。Zero copy 大大提高了应用程序的性能,减少不必要的内核缓冲区跟用户缓冲区间的拷贝,从而减少 CPU 的开销和减少了 kernel 和 user 模式的上下文切换,达到性能的提升。
 对应零拷贝技术有 mmap 及 sendfile

* mmap:小文件传输快
	RocketMQ 选择这种方式,mmap+write 方式,小块数据传输,效果会比 sendfile 更好。
	Java中的TransferTo()实现了Zero-Copy
* sendfile:大文件传输比mmap快

 应用:Kafka、Netty、RocketMQ 等都采用了零拷贝技术。


作者:Soulboy