揭开神秘的“位移主题”面纱 no.16

Kafka中神秘的内部主题(Internal Topic)__consumer_offsets。

consumer_offsets在Kafka源码中有个更为正式的名字,叫*位移主题*,即Offsets Topic。为了方便今天的讨论,我将统一使用位移主题来指代consumer_offsets。需要注意的是,它有两个下划线哦。

好了,我们开始今天的内容吧。首先,我们有必要探究一下位移主题被引入的背景及原因,即位移主题的前世今生。

在上一期中,我说过老版本Consumer的位移管理是依托于Apache ZooKeeper的,它会自动或手动地将位移数据提交到ZooKeeper中保存。当Consumer重启后,它能自动从ZooKeeper中读取位移数据,从而在上次消费截止的地方继续消费。这种设计使得Kafka Broker不需要保存位移数据,减少了Broker端需要持有的状态空间,因而有利于实现高伸缩性。

但是,ZooKeeper其实并不适用于这种高频的写操作,因此,Kafka社区自0.8.2.x版本开始,就在酝酿修改这种设计,并最终在新版本Consumer中正式推出了全新的位移管理机制,自然也包括这个新的位移主题。

新版本Consumer的位移管理机制其实也很简单,就是**将Consumer的位移数据作为一条条普通的Kafka消息,提交到**consumer_offsets中。可以这么说,**consumer_offsets的主要作用是保存Kafka消费者的位移信息。**它要求这个提交过程不仅要实现高持久性,还要支持高频的写操作。显然,Kafka的主题设计天然就满足这两个条件,因此,使用Kafka主题来保存位移这件事情,实际上就是一个水到渠成的想法了。

这里我想再次强调一下,和你创建的其他主题一样,位移主题就是普通的Kafka主题。你可以手动地创建它、修改它,甚至是删除它。只不过,它同时也是一个内部主题,大部分情况下,你其实并不需要“搭理”它,也不用花心思去管理它,把它丢给Kafka就完事了。

虽说位移主题是一个普通的Kafka主题,但它的消息格式却是Kafka自己定义的,用户不能修改,也就是说你不能随意地向这个主题写消息,因为一旦你写入的消息不满足Kafka规定的格式,那么Kafka内部无法成功解析,就会造成Broker的崩溃。事实上,Kafka Consumer有API帮你提交位移,也就是向位移主题写消息。你千万不要自己写个Producer随意向该主题发送消息。

你可能会好奇,这个主题存的到底是什么格式的消息呢?所谓的消息格式,你可以简单地理解为是一个KV对。Key和Value分别表示消息的键值和消息体,在Kafka中它们就是字节数组而已。想象一下,如果让你来设计这个主题,你觉得消息格式应该长什么样子呢?我先不说社区的设计方案,我们自己先来设计一下。

首先从Key说起。一个Kafka集群中的Consumer数量会有很多,既然这个主题保存的是Consumer的位移数据,那么消息格式中必须要有字段来标识这个位移数据是哪个Consumer的。这种数据放在哪个字段比较合适呢?显然放在Key中比较合适。

现在我们知道该主题消息的Key中应该保存标识Consumer的字段,那么,当前Kafka中什么字段能够标识Consumer呢?还记得之前我们说Consumer Group时提到的Group ID吗?没错,就是这个字段,它能够标识唯一的Consumer Group。

说到这里,我再多说几句。除了Consumer Group,Kafka还支持独立Consumer,也称Standalone Consumer。它的运行机制与Consumer Group完全不同,但是位移管理的机制却是相同的。因此,即使是Standalone Consumer,也有自己的Group ID来标识它自己,所以也适用于这套消息格式。

Okay,我们现在知道Key中保存了Group ID,但是只保存Group ID就可以了吗?别忘了,Consumer提交位移是在分区层面上进行的,即它提交的是某个或某些分区的位移,那么很显然,Key中还应该保存Consumer要提交位移的分区。

好了,我们来总结一下我们的结论。位移主题的Key中应该保存3部分内容:。如果你认同这样的结论,那么恭喜你,社区就是这么设计的!

接下来,我们再来看看消息体的设计。也许你会觉得消息体应该很简单,保存一个位移值就可以了。实际上,社区的方案要复杂得多,比如消息体还保存了位移提交的一些其他元数据,诸如时间戳和用户自定义的数据等。保存这些元数据是为了帮助Kafka执行各种各样后续的操作,比如删除过期位移消息等。但总体来说,我们还是可以简单地认为消息体就是保存了位移值。

当然了,位移主题的消息格式可不是只有这一种。事实上,它有3种消息格式。除了刚刚我们说的这种格式,还有2种格式:

  1. 用于保存Consumer Group信息的消息。
  2. 用于删除Group过期位移甚至是删除Group的消息。

第1种格式非常神秘,以至于你几乎无法在搜索引擎中搜到它的身影。不过,你只需要记住它是用来注册Consumer Group的就可以了。

第2种格式相对更加有名一些。它有个专属的名字:tombstone消息,即墓碑消息,也称delete mark。下次你在Google或百度中见到这些词,不用感到惊讶,它们指的是一个东西。这些消息只出现在源码中而不暴露给你。它的主要特点是它的消息体是null,即空消息体。

那么,何时会写入这类消息呢?一旦某个Consumer Group下的所有Consumer实例都停止了,而且它们的位移数据都已被删除时,Kafka会向位移主题的对应分区写入tombstone消息,表明要彻底删除这个Group的信息。

好了,消息格式就说这么多,下面我们来说说位移主题是怎么被创建的。通常来说,当Kafka集群中的第一个Consumer程序启动时,Kafka会自动创建位移主题。我们说过,位移主题就是普通的Kafka主题,那么它自然也有对应的分区数。但如果是Kafka自动创建的,分区数是怎么设置的呢?这就要看Broker端参数offsets.topic.num.partitions的取值了。它的默认值是50,因此Kafka会自动创建一个50分区的位移主题。如果你曾经惊讶于Kafka日志路径下冒出很多__consumer_offsets-xxx这样的目录,那么现在应该明白了吧,这就是Kafka自动帮你创建的位移主题啊。

你可能会问,除了分区数,副本数或备份因子是怎么控制的呢?答案也很简单,这就是Broker端另一个参数offsets.topic.replication.factor要做的事情了。它的默认值是3。

总结一下,如果位移主题是Kafka自动创建的,那么该主题的分区数是50,副本数是3

当然,你也可以选择手动创建位移主题,具体方法就是,在Kafka集群尚未启动任何Consumer之前,使用Kafka API创建它。手动创建的好处在于,你可以创建满足你实际场景需要的位移主题。比如很多人说50个分区对我来讲太多了,我不想要这么多分区,那么你可以自己创建它,不用理会offsets.topic.num.partitions的值。

不过我给你的建议是,还是让Kafka自动创建比较好。目前Kafka源码中有一些地方硬编码了50分区数,因此如果你自行创建了一个不同于默认分区数的位移主题,可能会碰到各种各样奇怪的问题。这是社区的一个Bug,目前代码已经修复了,但依然在审核中。

创建位移主题当然是为了用的,那么什么地方会用到位移主题呢?我们前面一直在说Kafka Consumer提交位移时会写入该主题,那Consumer是怎么提交位移的呢?目前Kafka Consumer提交位移的方式有两种:自动提交位移和手动提交位移。

Consumer端有个参数叫enable.auto.commit,如果值是true,则Consumer在后台默默地为你定期提交位移,提交间隔由一个专属的参数auto.commit.interval.ms来控制。自动提交位移有一个显著的优点,就是省事,你不用操心位移提交的事情,就能保证消息消费不会丢失。但这一点同时也是缺点。因为它太省事了,以至于丧失了很大的灵活性和可控性,你完全没法把控Consumer端的位移管理。

事实上,很多与Kafka集成的大数据框架都是禁用自动提交位移的,如Spark、Flink等。这就引出了另一种位移提交方式:手动提交位移,即设置enable.auto.commit = false。一旦设置了false,作为Consumer应用开发的你就要承担起位移提交的责任。Kafka Consumer API为你提供了位移提交的方法,如consumer.commitSync等。当调用这些方法时,Kafka会向位移主题写入相应的消息。

如果你选择的是自动提交位移,那么就可能存在一个问题:只要Consumer一直启动着,它就会无限期地向位移主题写入消息。

我们来举个极端一点的例子。假设Consumer当前消费到了某个主题的最新一条消息,位移是100,之后该主题没有任何新消息产生,故Consumer无消息可消费了,所以位移永远保持在100。由于是自动提交位移,位移主题中会不停地写入位移=100的消息。显然Kafka只需要保留这类消息中的最新一条就可以了,之前的消息都是可以删除的。这就要求Kafka必须要有针对位移主题消息特点的消息删除策略,否则这种消息会越来越多,最终撑爆整个磁盘。

Kafka是怎么删除位移主题中的过期消息的呢?答案就是Compaction。国内很多文献都将其翻译成压缩,我个人是有一点保留意见的。在英语中,压缩的专有术语是Compression,它的原理和Compaction很不相同,我更倾向于翻译成压实,或干脆采用JVM垃圾回收中的术语:整理。

不管怎么翻译,Kafka使用Compact策略来删除位移主题中的过期消息,避免该主题无限期膨胀。那么应该如何定义Compact策略中的过期呢?对于同一个Key的两条消息M1和M2,如果M1的发送时间早于M2,那么M1就是过期消息。Compact的过程就是扫描日志的所有消息,剔除那些过期的消息,然后把剩下的消息整理在一起。我在这里贴一张来自官网的图片,来说明Compact过程。

在这里插入图片描述
图中位移为0、2和3的消息的Key都是K1。Compact之后,分区只需要保存位移为3的消息,因为它是最新发送的。

Kafka提供了专门的后台线程定期地巡检待Compact的主题,看看是否存在满足条件的可删除数据。这个后台线程叫Log Cleaner。很多实际生产环境中都出现过位移主题无限膨胀占用过多磁盘空间的问题,如果你的环境中也有这个问题,我建议你去检查一下Log Cleaner线程的状态,通常都是这个线程挂掉了导致的。

小结

总结一下,今天我跟你分享了Kafka神秘的位移主题__consumer_offsets,包括引入它的契机与原因、它的作用、消息格式、写入的时机以及管理策略等,这对我们了解Kafka特别是Kafka Consumer的位移管理是大有帮助的。实际上,将很多元数据以消息的方式存入Kafka内部主题的做法越来越流行。除了Consumer位移管理,Kafka事务也是利用了这个方法,当然那是另外的一个内部主题了。

社区的想法很简单:既然Kafka天然实现了高持久性和高吞吐量,那么任何有这两个需求的子服务自然也就不必求助于外部系统,用Kafka自己实现就好了。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

机器视觉分析在加油站安全中的应用:使用手机检测、打电话行为识别

在加油站等高危场所,禁止使用手机是为了防止潜在的火灾和爆炸风险。手机在使用过程中可能产生电火花,而在加油站这种易燃易爆环境中,任何电火花都可能引发严重的安全事故。因此,加油站禁止使用手机是保障安全生产的重要措施。基于…

如何让Google快速收录?

要让Google快速收录你的网站,可以考虑使用GSI服务,这是一种专门设计来加速网站被Google搜索引擎收录的服务,下面详细解释GSI服务的基本原理和具体好处: GSI服务通过一种名为GPC爬虫池的系统实现,这个系统是基于对Goog…

SQL注入攻击是什么?如何预防?

一、SQL注入攻击是什么? SQL注入攻击是一种利用Web应用程序中的安全漏洞,将恶意的SQL代码插入到数据库查询中的攻击方式。攻击者通过在Web应用程序的输入字段中插入恶意的SQL代码,然后在后台的数据库服务器上解析执行这些代码,从而…

对比方案:5款知识中台工具的优缺点详解

知识中台工具为企业和组织高效地组织、存储和分享知识,还能提升团队协作的效率。在选择搭建知识中台的工具时,了解工具的优缺点,有助于企业做出最佳决策。本文LookLook同学将对五款搭建知识中台的工具进行优缺点的简单介绍,帮助企…

单细胞分析(Signac): PBMC scATAC-seq 基因组区域可视化

引言 在本教学指南中,我们将探讨由10x Genomics公司提供的人类外周血单核细胞(PBMCs)的单细胞ATAC-seq数据集。 加载包 首先加载 Signac、Seurat 和我们将用于分析人类数据的其他一些包。 if (!requireNamespace("EnsDb.Hsapiens.v75&qu…

虹科Pico汽车示波器 | 免拆诊断案例 | 2017款吉利帝豪GL车发动机偶尔无法起动

故障现象  一辆2017款吉利帝豪GL车,搭载JLC-4G18发动机和手动变速器,累计行驶里程约为39.3万km。车主反映,该车发动机偶尔无法起动。故障发生频率比较频繁,冷机状态下故障比较容易出现。 故障诊断  接车后试车,故…

1Panel开源面板全平台下载总量突破500,000次!

截至2024年5月22日,FIT2CLOUD飞致云旗下开源项目——1Panel开源Linux服务器运维管理面板全平台下载总量突破500,000次!

Java培训后找不到工作,现在去培训嵌入式可行吗?

最近java 工作还是比较好找,不知道你是对薪资要求太高,还是因为其他原因,如果你真的面试了很多都还找不到工作,那么一定要知道找不到工作的原因是啥,一定不是因为java 太卷,你说那个行业,那个职…

socks5 如何让dns不被污染

问题 发现firefox浏览器代理设置成socks5后,查看ip是成功了,但是谷歌等海外的还是无法正常访问。 原因 主要原因是socks5连接虽然是成功了,但是dns还是走国内的,国内的dns解析都被污染了导致没法正常访问 解决 把设置里的 使…

工程文档CAD转换必备!快速将 DWG 转换到 PNG ~

Aspose.CAD 是一个独立的类库,以加强Java应用程序处理和渲染CAD图纸,而不需要AutoCAD或任何其他渲染工作流程。该CAD类库允许将DWG, DWT, DWF, DWFX, IFC, PLT, DGN, OBJ, STL, IGES, CFF2文件、布局和图层高质量地转换为PDF和光栅图像格式。 Aspose AP…

springboot学生就业信息管理系统-计算机毕业设计源码95340

摘 要 信息化社会内需要与之针对性的信息获取途径,但是途径的扩展基本上为人们所努力的方向,由于站在的角度存在偏差,人们经常能够获得不同类型信息,这也是技术最为难以攻克的课题。针对学生就业信息管理系统等问题,对…

Spire.PDF for .NET【文档操作】演示:将PDF 拆分为多个 PDF

Spire.PDF 完美支持将多页 PDF 拆分为单页。但是,更常见的情况是,您可能希望提取选定的页面范围并保存为新的 PDF 文档。在本文中,您将学习如何通过 Spire.PDF 在 C#、VB.NET 中根据页面范围拆分 PDF 文件。 Spire.PDF for .NET 是一款独立 …

Python-3.12.0文档解读-内置函数pow()详细说明+记忆策略+常用场景+巧妙用法+综合技巧

一个认为一切根源都是“自己不够强”的INTJ 个人主页:用哲学编程-CSDN博客专栏:每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 详细说明 功能描述 参数 返回值 使用规则 示例代码 基本使用 模运算 变动记录…

CAD石墨烯生成器 V1.0 渊鱼

插件介绍 CAD石墨烯生成器插件可用于在AutoCAD软件内参数化建立石墨烯几何模型。插件建立石墨烯的球棍模型,可控制模型的尺寸、碳原子环的尺寸、原子直径、化学键直径,并可控制模型的起伏形态。插件生成的实体模型可进行修改或绘图渲染,用于…

Java多线程(02)—— 线程等待,线程安全

一、如何终止线程 终止线程就是要让 run 方法尽快执行结束 1. 手动创建标志位 可以通过在代码中手动创建标志位的方式,来作为 run 方法的执行结束条件; public static void main(String[] args) throws InterruptedException {boolean flag true;Thr…

快速下载极客时间课程

仅供学习,切勿商用 1. 下载 下载geektime-downloader,安装到指定文件夹,注意路径尽量不要出现汉字 不想去github上下载的可以直接下载文章顶部的软件安装包。 2. 执行命令 在安装geektime-downloader目录下,点击鼠标右键&…

C++之运算符重载

1、运算符重载 //Complex.h #ifndef _COMPLEX_H_ #define _COMPLEX_H_class Complex { public:Complex(int real_, int imag_);Complex();~Complex();Complex& Add(const Complex& other); void Display() const;Complex operator(const Complex& other);privat…

Linux中常见的基本指令(上)

目录 一、ls指令 1. ls 2. ls -l 3. ls -a 4.ls -F 二、qwd指令 三、cd指令 1. cd .. 2. cd / / / 3. cd ../ / / 4. cd ~ 5. cd - 五、mkdir指令 六、rmdir指令和rm指令 一、ls指令 语法 : ls [ 选项 ][ 目录或文件 ] 。 功能 :对于目录…

手机号码携号转网查询保障用户权益、信息透明、优化用户体验

携号转网服务是指在同一本地网范围内,蜂窝移动通信用户(不含物联网用户)变更签约的基础电信业务经营者而用户号码保持不变的一项服务。近年来,随着通信行业的不断发展,携号转网服务已成为满足用户个性化需求、提升服务…

VBA让按钮消失

要求 用VBA搞小程序,有个录入数据的按钮,点击后进行录入数据的操作,操作完成后这个按钮就是灰的,点不动,这个怎么做? 实现过程 没找到让按钮变灰的方法,退而求其次,让按钮消失。 …