深入浅出消息队列----【RocketMQ 和 Kafka 消息存储差异对比】

news2024/9/29 7:27:40

深入浅出消息队列----【RocketMQ 和 Kafka 消息存储差异对比】

  • RocketMQ 的消息存储
  • Kafka 的消息存储
  • 对比 RocketMQ 与 Kafka

本文仅是文章笔记,整理了原文章中重要的知识点、记录了个人的看法
文章来源:编程导航-鱼皮【yes哥深入浅出消息队列专栏】

RocketMQ 的消息存储

RocketMQ 采用多 Topic 混合存储的一个文件的方式来保存消息,即一个 CommitLog 文件中会包含分给此 Broker 的所有消息,不论消息属于哪个 Topic 的哪个 Queue。

请添加图片描述

也就是说 RocketMQ 是以 Broker 为单位将此 Broker 收到的所有消息放到一个文件中(当然,当 commitlog 超过 1G,新起一个 commitlog)。

然后再以 Topic + 队列维度,存储 consumeQueue,消费者具体是通过 consumeQueue 得到消息的真实物理地址再去访问 commitLog 获取消息的,所有 consumeQueue 可理解为消息的索引。

每条消息存储至 commitlog,都会在对应的 consumeQueue 生成一条记录,因此这个索引也叫稠密索引

Kafka 的消息存储

kafka 和 RocketMQ 一样,Topic 下也分了多个队列提高消费的并发度,但是在 kafka 中不叫队列,叫分区(Partition)。

kafka 对消息存储和 rocketmq 不一样,它是以 partition 为单位来存储消息的:

请添加图片描述

可以看到,每个 Topic 的每个分区都会拥有自己的消息文件,且对应会有索引文件(还有一个时间索引文件这里不多介绍),它们的文件名一样(后缀不同)。

请添加图片描述

都以文件存储的第一条消息的 offset 作为文件名,当一个文件写满会新起一个文件(和 RocketMQ 的一样)。

不同分区的消息是顺序写入到对应的文件中,也就是在存储上,相同 Topic 且相同分区的消息被存储到一个文件中,这跟 RocketMQ 的混合存储时完全不一样的。

并且索引文件的设计也不一样,kafka 不会为每条消息都对应生成一个索引,而是每隔几条消息再创建一条索引,这样能节省空间,能在内存中保存更多的索引,这样的索引叫稀疏索引

稠密索引的查找逻辑我们很清楚,那稀疏索引是如何查找到对应的消息的呢?

首先通过 offset 找到对应的索引文件,再通过二分法遍历索引文件找到离目标消息最近的索引,再通过二分法遍历索引文件找到离目标消息最近的索引,再利用这个索引内容从消息文件找到最近这条消息的位置,再从这个位置开始顺序遍历消息文件找到目标消息。

这样一次寻址的时间复杂度为 O(logn) + O(m),其中 n 为索引文件中的索引个数,m 为索引的稀疏程度。

相比之下,RocketMQ 的消息寻址则是根据消息 offset,直接计算消息在索引中的实际位置(索引长度固定,直接 offset * 长度),然后得到消息在 commitlog 中的物理位置以及消息长度,直接从 commitlog 获取消息,一次寻址的时间复杂度为 O(1)。

这其实就是空间和时间的权衡了,kafka 用更少的空间就需要花费更多的空间,而 RocketMQ 用的时间更少却花了更多的空间。

没有对错,只有各自权衡利弊,选择最合适自己的。

其实这个 kafka 索引的二分查找也很有讲究,不是朴素的二分查找,而是经过工程优化冷热分区的二分查找

上篇文章中提到了 pageCache,文件的读取都是会先经过 pageCache 缓存一道,而这个 pageCache 占用的就是内存资源。

如果按照正常的二分查找,那么需要读取索引的头和尾内容,尾的内容是最新写入的,很有可能已经在 pageCache,而头的内容可能是很久之前的,很大概率不在 pageCache 中,因此需要从磁盘加载读取到 pageCache。

内存的资源是有限的,操作系统会通过类 LRU 机制淘汰内存,当内存不足,很有可能因为加载这些很久以前的数据,导致内存中一些最近的 pageCache 被置换到磁盘中,而最近的 pageCache 的消息正常而言是近期会被消费者读取消费的,但这些消息又被挤出了内存,这样一来对性能就不好了。

且按照一般的逻辑,消费者要拉取的消息肯定是在索引文件的尾部,也就是最近写入的,而不是时间久远的头部,从头部找意义不大。

请添加图片描述

因此 kafka 给索引文件做了冷热分区,修改过的二分时先查热区的二分,如果查不到再从冷区开始,由于热区的数据本身都已经在 pageCache 中,因此对缓存友好,不会污染缓存,且很大可能性能知道对应的消息。

请添加图片描述

对比 RocketMQ 与 Kafka

从上文可以知道,两者有很多的相似之处,比如都有对应的索引文件,消息都是追加写入,都是先通过索引再找到消息等等。

但,不同点在于 RocketMQ 是将不同 Topic 消息都混合存储到一个文件中,而 Kafka 则是以分区为单位存储文件。

相比之下 Kafka 的存储结构在数据复制和迁移上更加令狐,迁移一个分区直接拷贝文件就行了,而 RocketMQ 由于一个文件混合存储了所有的 Topic 的消息,因此很不灵活。

那从性能来看,它们之间这样的设计有什么显著的区别吗?

之前的文章提到了顺序读写的问题,像 RocketMQ 将所有消息都追加顺序写入到 commitlog 这个文件中,因此它是顺序写,且消费者按序获取最新的消息,虽然不同消费者并发消费时拉取消息不是完全按照顺序读取的,但是从整体来看也近似于顺序读。

请添加图片描述

Kafka 其实也遵循这个规律,对每个 Partition 文件来说,消息都是顺序追加写入,遵循顺序写,对消费而言,每个分区都是顺序读,但这一切都得在少量 Topic 和少量 Partition 的前提下。

想象一下,如果一个 Broker 中有海量的 Topic 或者 Partition,那么对于 Kafka 而言就需要增加海量的消息文件,那么不同 Partition 消息的写入意味着需要频繁切换不同文件来写入,对每个文件而言确实顺序写,但是从全局来看这是随机写

不同文件之前的存储不能保证连续,磁盘需要各种寻道,这样一来性能就会显著下降,同理对消息的读取也是一样的,全局看来就是随机读,因为需要奇幻很多文件来读取消息。

因为海量 Topic 或 Partition 场景下,Kafka 的性能就会显著下降,而 RocketMQ 没有这个烦恼,这就是混合存储的好处。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1980453.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

指南!网上卖药品需要什么资质?

随着互联网技术的飞速发展,医药电商已经成为药品和医疗器械销售的重要渠道。处方药的网络销售政策逐步放宽,医药电商行业迎来了快速发展的春天。在这一领域,主要的参与者包括药品销售公司和电商平台。 为了吸引流量和满足处方药审方的需求&a…

第18课 Scratch入门篇:时钟-当前时间

时钟 故事背景: 在一个遥远的科技星球上,时间对于居民们来说无比珍贵。这个星球上的居民们都是技术高手,他们使用先进的编程技术来管理自己的生活。然而,星球上的时间系统最近出现了故障,导致时间的流逝变得不稳定。为…

【终极指南】大模型二次开发:从零基础到高手之路

随着人工智能技术的发展,预训练的大模型(例如GPT系列、BERT等)已成为自然语言处理领域的关键技术之一。对于开发者来说,掌握如何基于这些大模型进行二次开发,不仅可以提升自身的技术实力,还能为企业带来更多…

Flink 如何处理背压

文章目录 目录 前言 一、什么是背压? 二、处理背压的步骤 1.模拟背压机制 2.为什么要关心背压问题? 总结 前言 初次接触Flink的同学会对背压有很多的疑问。本文就是我学习的一些心得和体会,以及借鉴一些文章的感想。 Flink 如何处理背压效应…

使用snap的安装docker配置阿里云镜像加速

使用snap安装docker非常的简单,一条命令即可 snap install docker 但是通过这个命令安装的docker, 配置阿里云镜像跟常规安装的配置起来不太一样, 下面讲一下配置流程 修改docker配置文件/var/snap/docker/current/config/daemon.json 这个文件应该是已经创建好…

重磅!LangChain 官方发布 Agent IDE!!

1 LangChain 开发现状 LangChain 从应用开发框架出发,提供了一套代码级工具集,旨在降低 LLM 的开发难度,在过去一年中吸引了众多开发者,助力他们迅速打造 AI 大模型应用。然而,还有一群用户,他们希望门槛…

NC 最长无重复子数组

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女通用,看懂了就去分享给你的码吧。 描述 给定一个长度…

idea连接oracle

配置 注意: SID指的是实例名称

C语言宠物系统3

在前面的基础上,加上了修改功能和排序功能,可以选择姓名排序,年龄排序,价格排序。 test.c源文件 #include "Pet.h"void menu() {printf("------------------------\n");printf("- 欢迎来到宠物商店 …

实践出真知:Agents 领域“一年打怪升级”的经验分享

编者按:在你构建 AI Agents 时,是否曾遇到这些困扰:总是在简单任务上出错,从而让你有时会怀疑自己的技术水平?面对客户的需求,AI Agent 表现得像个“笨蛋”,无法准确理解和执行指令?…

不同网络上的计算机怎么通信

从 一个网络上计算机的通信 ,我们知道,在一个网络里,多台主机通过交换机连接起来,每台主机的网卡有全球唯一的 MAC 地址,一个网络上的主机通过 MAC 地址通信。 那么,多个网络之间如何互联和通信&#xff1…

【轨物方案】智慧供热物联网整体解决方案

目前城市供暖系统当中,供暖设备一直得不到更新和升级,没有合理的监控设备,导致对供暖的合理调控不理想,供暖严重失调而浑然不知,进而出现冷热不均的问题,极易造成资源严重浪费。缺乏成熟的管理系统&#xf…

上门按摩小程序项目开发功能介绍

上门按摩小程序通常设计为连接按摩服务提供者和客户的平台,提供便捷的预约和服务管理功能。以下是这类小程序可能包含的功能: 用户注册和登录: 用户可以注册个人账户并登录,以便管理个人信息和预约记录。 按摩师信息浏览&#xf…

JAVA中实现线程安全的三种方式

JAVA中实现线程安全的三种方式 1. 同步代码块2. 同步方法3. ReentrantLock4. 总结 💖The Begin💖点点关注,收藏不迷路💖 1. 同步代码块 使用synchronized关键字加在需要同步的代码块上,并指定一个锁对象。这种方式可以…

Java作用域

目录 1.作用域 基本使用 2.作用域的注意事项和细节使用 1.作用域 基本使用 局部变量一般是成员方法里的变量 。全局变量有默认值,局部变量没有默认值。 在类内但是方法外定义的变量是局部变量,有初始值0可以不赋初值,在方法内的是局部变量…

本机IP地址可以随便改吗?怎样修改本机IP地址

在当今数字化时代,IP地址作为设备在网络中的唯一标识,扮演着至关重要的角色。然而,许多用户对于IP地址的修改存在诸多疑问,尤其是关于其是否可以随意更改以及如何操作。本文旨在深入探讨这些问题,帮助读者理解本机IP地…

电信流量卡合约期内可以强制注销吗?这篇文章终于说清楚了!

流量卡在注销的时候,却被告知在合约期内不能注销,要注销的话就要交违约金,这种情况你遇到过没有?其实合约期内也是可以注销流量卡的,只不过方法你没有用对! 今天靠谱教大家怎么注销合约期内的流量卡&#…

算法day05 优先级队列 桶排序

3.详解桶排序以及排序内容大总结_哔哩哔哩_bilibili 优先级队列: java提供有PriorityQueue类,如果没有提供优先级队列,例如c语言,需要先创建优先级队列,按需求创建的优先级队列通常效率更高。 默认创建priority对象数据…

【QT】Qt 网络

Qt 网络 Qt 网络1. UDP Socket(1)核心 API 概览(2)回显服务器(3)回显客户端 2. TCP Socket(1)核心 API 概览(2)回显服务器(3)回显客户…