与天地兮比寿,与日月兮齐光。这篇文章主要讲述#yyds干货盘点#Alibaba中间件技术系列「RocketMQ技术专题」让我们一同来看看RocketMQ和Kafka索引设计相关的知识,希望能为你提供帮助。
背景介绍
文件索引,是存储设计的关键,一个好的索引,应该能够在最短的时间里,找到你想要的数据,同时,还能尽量少的使用内存或磁盘空间。但是这里说的索引并不是指mysql或者NoSQL这些数据库索引,而是MQ中间件的索引。相对而言较为简单的MQ索引。我们可以通过研究MQ的索引,看看他们为何如此设计,我们又有哪些借鉴之处,并且也可以根据他们索引文件的设计模式,进行分析他们的性能问题,接下来我们借来分别说说RocketMQ和Kafka的索引设计原理,重点我们会介绍RocketMQ的设计。
RocketMQ
相比较Kafka的分区索引文件的设计方案,RocketMQ的数据文件属于混合存储,即,所有的topic数据都放在一个文件里,因此,读数据的时候,就无法做到连续读了,只能随机读。所以,RocketMQ推荐使用大内存,利用PageCache 预读机制把commitlog数据缓存起来,混合存储的好处则是能够承受万级别的队列数量。kafka 64分区有些夸张,单机单磁盘1000分区还是没啥问题的,经验之谈最好别超过 2000,RocketMQ 提供基于MsgID搜索消息的方案,即,每条消息,都有一个唯一的 ID,
Message IDID由broker IP + Port + CommitLog Offset 组成,通过这两个参数,可快速定位到一条消息。注意,Kafka是没有这个功能的,但理论上,通过 Kafka 的 offset 也是可以找到具体的消息的。
另外 RocketMQ 有 2 种索引。
- 消息消费索引
- Hash 查询索引
RocketMQ的存储层架构
RocketMQ 的运作流程图
RocketMQ 的存储设计图:消息被不停的 append 到 commitlog,然后,再构建消费索引,如果没有这个索引,consumer 要在 commitlog 里消费消息,那可真是太难了。
每个consumerQueue文件里存放着 30w 个元素,每个元素 20 字节,8 字节 offset ,4 字节 size, 8 字节 tag hashcode,因此,每个文件也就 5.8MB 不到,很轻量。
Hash查询索引(我们可以称之为tag)Hash查询索引,主要是根据 Key 来快速查询消息,属于一种附加功能。RocketMQ 采用了 java HashMap 的思想,实现了 Hash 索引的存储。
- 如果这个 Map 有 500w 个 slot,每个 slot 的链表长度为 4. 如果我们使用一个 key 进行消息查找,他的过程是这样的:先 hash key 得到 hashCode,然后对 500w 取余,找到槽位,这个槽位大小是4个字节,保存了链表尾部的具体元素地址。
- 而这个链表元素的大小是 20 个字节,保存了 key 的 hash 值,commitlog offset,时间戳,还有他下一个链表节点的地址。
- 为什么在 链表元素里保存 了 hash 值呢?为了防止 hash 值不同,但是 hash 取模后的结果相同(也就是 hash 冲突),如果冲突了,就用 hash 值比对一下。
- 那如果 hash 值相同,key 内容不同呢?RocketMQ 的做法是放在客户端过滤。
Kafka 每个 topic 有多个 partition ,每个 partition 有多个 segment,每个 segment 里,存储了消息的相关文件:数据文件,索引文件。Kafka 不像 RocketMQ,所有数据都存在一个文件里,Kafka 每个 topic 的文件都是隔离开的,而每个 topic 又可能会有很多的 partition(看你的配置),因此,如果你的topic非常多,或者你的partition非常多的话,顺序写就会变成随机写,性能会骤降。
Kafka 的索引文件和数据文件绑定在一起的。与RocketMQ的消费索引类似,Kafka 里面是逻辑 offset 映射物理 offset ,并且采用了稀疏索引的方式。然后,我们看看他们的索引设计,如下图:[逻辑索引,偏移量]
- 逻辑索引,即这个 partition下的全局递增逻辑索引(当然,这个是相对偏移量,这里为了描述简单,就不区分了)
- 偏移量,表示这条消息的所在文件的物理 position。
基于 partition 的分区原子计数器。使用 broker ID + 分区 ID + 计数器 就可以标识一条唯一的消息。然后,用计数器映射 偏移量 offset,简直就是完美。然后,为了达到搜索效率和空间消耗的平衡,边稠密索引为稀疏索引。RocketMQ 和 Kafka 的索引设计相似之处:
RocketMQ 的 topic 和 kafka 的 topic 类似,RocketMQ 的 queue 和 kafka 的 partition 类似,都是为了 scale out。
- RocketMQ 为每个 queue 设计了 consumerQueue 索引文件,每个文件大小固定 5.8MB;
- Kafka 为每个 partition 设计了 segment (.index + .log)。
和 Kafka 的索引设计的最大不同
【#yyds干货盘点#Alibaba中间件技术系列「RocketMQ技术专题」让我们一同来看看RocketMQ和Kafka索引设计】RocketMQ 是所有 topic 混合存储,目的是支持更多的topic,而 Kafka 的topic 是单独存储,好处是顺序读性能好,另外,根据分区做副本也比较好做。
推荐阅读
- 站在面试官角度,看求职与内卷
- Go 分布式令牌桶限流 + 兜底策略
- springBoot报错( MyBatis:check the manual that corresponds to your MySQL server version)
- 关于dart中的late关键字,你了解多少(#yyds干货盘点#)
- 华为策略路由应用案例
- #yyds干货盘点# 滴滴二面(Kafka是如何读写副本消息的())
- #yyds干货盘点#分布式服务追踪Spring Cloud Sleuth
- 谷歌大神Jeff Dean领衔,万字展望5大AI趋势
- #yyds干货盘点#会话管理