Kafka 的 Lag 计算误区及正确实现

【本人秃顶程序员】Kafka 的 Lag 计算误区及正确实现 ←←←←←←←←←←←← 快,点关注! 前言 消息堆积是消息中间件的一大特色,消息中间件的流量削峰、冗余存储等功能正是得益于消息中间件的消息堆积能力。然而消息堆积其实是一把亦正亦邪的双刃剑,如果应用场合不恰当反而会对上下游的业务造成不必要的麻烦,比如消息堆积势必会影响上下游整个调用链的时效性,有些中间件如RabbitMQ在发生消息堆积时在某些情况下还会影响自身的性能。对于Kafka而言,虽然消息堆... 阅读详情

前言

消息堆积是消息中间件的一大特色,消息中间件的流量削峰、冗余存储等功能正是得益于消息中间件的消息堆积能力。然而消息堆积其实是一把亦正亦邪的双刃剑,如果应用场合不恰当反而会对上下游的业务造成不必要的麻烦,比如消息堆积势必会影响上下游整个调用链的时效性,有些中间件如RabbitMQ在发生消息堆积时在某些情况下还会影响自身的性能。对于Kafka而言,虽然消息堆积不会对其自身性能带来多大的困扰,但难免不会影响上下游的业务,堆积过多有可能会造成磁盘爆满,或者触发日志清除策略而造成消息丢失的情况。如何利用好消息堆积这把双刃剑,监控是最为关键的一步。

正文

消息堆积是消费滞后(Lag)的一种表现形式,消息中间件服务端中所留存的消息与消费掉的消息之间的差值即为消息堆积量,也称之为消费滞后(Lag)量。对于Kafka而言,消息被发送至Topic中,而Topic又分成了多个分区(Partition),每一个Partition都有一个预写式的日志文件,虽然Partition可以继续细分为若干个段文件(Segment),但是对于上层应用来说可以将Partition看成最小的存储单元(一个由多个Segment文件拼接的“巨型文件”)。每个Partition都由一系列有序的、不可变的消息组成,这些消息被连续的追加到Partition中。我们来看下图,其就是Partition的一个真实写照:

上图中有四个概念:

  1. LogStartOffset:表示一个Partition的起始位移,初始为0,虽然消息的增加以及日志清除策略的影响,这个值会阶段性的增大。
  2. ConsumerOffset:消费位移,表示Partition的某个消费者消费到的位移位置。
  3. HighWatermark:简称HW,代表消费端所能“观察”到的Partition的最高日志位移,HW大于等于ConsumerOffset的值。
  4. LogEndOffset:简称LEO, 代表Partition的最高日志位移,其值对消费者不可见。比如在ISR(In-Sync-Replicas)副本数等于3的情况下(如下图所示),消息发送到Leader A之后会更新LEO的值,Follower B和Follower C也会实时拉取Leader A中的消息来更新自己,HW就表示A、B、C三者同时达到的日志位移,也就是A、B、C三者中LEO最小的那个值。由于B、C拉取A消息之间延时问题,所以HW必然不会一直与Leader的LEO相等,即LEO>=HW。

要计算Kafka中某个消费者的滞后量很简单,首先看看其消费了几个Topic,然后针对每个Topic来计算其中每个Partition的Lag,每个Partition的Lag计算就显得非常的简单了,参考下图:

由图可知消费Lag=HW - ConsumerOffset。对于这里大家有可能有个误区,就是认为Lag应该是LEO与ConsumerOffset之间的差值。LEO是对消费者不可见的,既然不可见何来消费滞后一说。

那么这里就引入了一个新的问题,HW和ConsumerOffset的值如何获取呢?

首先来说说ConsumerOffset,Kafka中有两处可以存储,一个是Zookeeper,而另一个是”**consumer_offsets这个内部topic中,前者是0.8.x版本中的使用方式,但是随着版本的迭代更新,现在越来越趋向于后者。就拿1.0.0版本来说,虽然默认是存储在”**consumer_offsets”中,但是保不齐用于就将其存储在了Zookeeper中了。这个问题倒也不难解决,针对两种方式都去拉取,然后哪个有值的取哪个。不过这里还有一个问题,对于消费位移来说,其一般不会实时的更新,而更多的是定时更新,这样可以提高整体的性能。那么这个定时的时间间隔就是ConsumerOffset的误差区间之一。

再来说说HW,其也是Kafka中Partition的一个状态。有可能你会察觉到在Kafka的JMX中可以看到“kafka.log:type=Log,name=LogEndOffset,topic=[topic_name],partition=[partition_num]”这样一个属性,但是这个值不是LEO而是HW。

那么怎样正确的计算消费的Lag呢?对Kafka熟悉的同学可能会想到Kafka中自带的kafka-consumer_groups.sh脚本中就有Lag的信息,示例如下:

[root@node2 kafka_2.12-1.0.0]# bin/kafka-consumer-groups.sh --describe --bootstrap-server localhost:9092 --group CONSUMER_GROUP_ID
TOPIC                PARTITION  CURRENT-OFFSET  LOG-END-OFFSET  LAG        CONSUMER-ID                                       HOST                   CLIENT-ID
topic-test1          0          1648            1648            0          CLIENT_ID-e2d41f8d-dbd2-4f0e-9239-efacb55c6261    /192.168.92.1          CLIENT_ID
topic-test1          1          1648            1648            0          CLIENT_ID-e2d41f8d-dbd2-4f0e-9239-efacb55c6261    /192.168.92.1          CLIENT_ID
topic-test1          2          1648            1648            0          CLIENT_ID-e2d41f8d-dbd2-4f0e-9239-efacb55c6261    /192.168.92.1          CLIENT_ID
topic-test1          3          1648            1648            0          CLIENT_ID-e2d41f8d-dbd2-4f0e-9239-efacb55c6261    /192.168.92.1          CLIENT_ID

我们深究一下kafka-consumer_groups.sh脚本,发现只有一句代码:

exec $(dirname $0)/kafka-run-class.sh kafka.admin.ConsumerGroupCommand "$@"

其含义就是执行kafka.admin.ConsumerGroupCommand而已。进一步深究,在ConsumerGroupCommand内部抓住了2句关键代码:

val consumerGroupService = new KafkaConsumerGroupService(opts)
val (state, assignments) = consumerGroupService.describeGroup()

代码详解:consumerGroupService的类型是ConsumerGroupServicesealed trait类型),而KafkaConsumerGroupService只是ConsumerGroupService的一种实现,还有一种实现是ZkConsumerGroupService,分别对应新版的消费方式(消费位移存储在__consumer_offsets中)和旧版的消费方式(消费位移存储在zk中),详细计算步骤参考下一段落的内容。opt参数是指“ –describe –bootstrap-server localhost:9092 –group CONSUMER_GROUP_ID”等参数。第2句代码是调用describeGroup()方法来获取具体的信息,即二元组中的assignments,这个assignments中保存了上面打印信息中的所有内容。

Scala小知识:
在Scala中trait(特征)相当于Java的接口,实际上它比接口更大强大。与Java中的接口不同的是,它还可以定义属性和方法的实现(JDK8起的接口默认方法)。一般情况下Scala中的类只能继承单一父类,但是如果是trait的话就可以继承多个,从结果来看是实现了多重继承。被sealed声明的trait仅能被同一文件的类继承。

ZkConsumerGroupService中计算消费lag的步骤如下:

  1. 通过zk获取一些基本信息,对应上面打印信息中的:TOPIC、PARTITION、CONSUMER-ID等,不过不会有HOST和CLIENT-ID。
  2. 通过OffsetFetchRequest请求获取消费位移(offset),如果获取失败则在通过zk获取。
  3. 通过OffsetReuqest请求获取分区的LogEndOffset(简称为LEO,可见的LEO)。
  4. 计算LogEndOffset与消费位移的差值来获取lag。

KafkaConsumerGroupService中计算消费lag的步骤如下:

  1. 通过DescibeGroupsRequest请求获取一些基本信息,不仅包括TOPIC、PARTITION、CONSUMER-ID,还有HOST和CLIENT-ID。其实还有通过
    FindCoordinatorRequest请求来获取coordinator信息,如果不了解coordinator在这里也没影响。
  2. 通过OffsetFetchRequest请求获取消费位移。
  3. 通过OffsetReuqest请求获取分区的LogEndOffset(简称为LEO)。
  4. 计算LogEndOffset与消费位移的差值来获取lag。

可以看到KafkaConsumerGroupService与ZkConsumerGroupService的计算Lag的方式都差不多,但是KafkaConsumerGroupService能获取更多消费详情,并且ZkConsumerGroupService也被标注为@Deprecated的了,后面内容都针对KafkaConsumerGroupService来做说明。既然Kafka已经为我们提供了线程的方法来获取Lag,那么我们有何必再重复造轮子,这里笔者写了一个调用的KafkaConsumerGroupService的示例(KafkaConsumerGroupService是使用Scala语言编写的,在Java的程序里使用类似scala.collection.Seq这样的全名称以防止混淆):

String[] agrs = {"--describe", "--bootstrap-server", brokers, "--group", groupId};
ConsumerGroupCommand.ConsumerGroupCommandOptions opts =
        new ConsumerGroupCommand.ConsumerGroupCommandOptions(agrs);
ConsumerGroupCommand.KafkaConsumerGroupService kafkaConsumerGroupService =
        new ConsumerGroupCommand.KafkaConsumerGroupService(opts);
scala.Tuple2<scala.Option<String>, scala.Option<scala.collection.Seq<ConsumerGroupCommand
        .PartitionAssignmentState>>> res = kafkaConsumerGroupService.describeGroup();
scala.collection.Seq<ConsumerGroupCommand.PartitionAssignmentState> pasSeq = res._2.get();
scala.collection.Iterator<ConsumerGroupCommand.PartitionAssignmentState> iterable = pasSeq.iterator();
while (iterable.hasNext()) {
    ConsumerGroupCommand.PartitionAssignmentState pas = iterable.next();
    System.out.println(String.format("\n%-30s %-10s %-15s %-15s %-10s %-50s%-30s %s",
            pas.topic().get(), pas.partition().get(), pas.offset().get(),
            pas.logEndOffset().get(), pas.lag().get(), pas.consumerId().get(),
            pas.host().get(), pas.clientId().get()));
}

在使用时,你可以封装一下这段代码然后返回一个类似List<ConsumerGroupCommand.PartitionAssignmentState>的东西给上层业务代码做进一步的使用。ConsumerGroupCommand.PartitionAssignmentState的代码如下:

case class PartitionAssignmentState(
  group: String, coordinator: Option[Node], topic: Option[String],
  partition: Option[Int], offset: Option[Long], lag: Option[Long],
  consumerId: Option[String], host: Option[String],
  clientId: Option[String], logEndOffset: Option[Long])

Scala小知识:
对于case class, 在这里你可以简单的把它看成是一个JavaBean,但是它远比JavaBean强大,比如它会自动生成equals、hashCode、toString、copy、伴生对象、apply、unapply等等东西。在 scala 中,对保护(Protected)成员的访问比 java 更严格一些。因为它只允许保护成员在定义了该成员的的类的子类中被访问。而在java中,用protected关键字修饰的成员,除了定义了该成员的类的子类可以访问,同一个包里的其他类也可以进行访问。Scala中,如果没有指定任何的修饰符,则默认为 public。这样的成员在任何地方都可以被访问。

如果你正在试着运行上面一段程序,你会发现编译失败,报错:cannot access ‘kafka.admin.ConsumerGroupCommand.PartitionAssignmentState’ in ‘kafka.admin.ConsumerGroupCommand‘。这时候需要将所引入的kafka.core包中的kafka.admin.ConsumerGroupCommand中的PartitionAssignmentState类前面的protected修饰符去掉才能编译通过。

消费者组Rebalance的蝴蝶效应:从Lag暴增看Kafka分区分配策略优化 本文深入解析Kafka消费者组Rebalance操作如何引发Lag暴增问题,探讨分区分配策略(如Range和RoundRobin)的优缺点,并提出StickyAssignor等优化方案。通过实际案例和性能对比,展示如何在大规模分布式系统中有效减少Rebalance带来的性能波动,确保消息处理的稳定性和实时性。 阅读详情

相关推荐

kafka的lag(kafka的消费堆积)为什么有时是负数?

Kafka Manager先从zookeeper获取LogSize,再从kafka __consumer_offsets topic读取Offset。由于这两步操作存在时间间隔,因此吞吐很大的topic或者当前集群负载很高的时候就会出现Offset > LogSize的情况。

yonggeit的博客 5212

深入解析Kafka中的Lag现象

本文将带您深入研究Apache Kafka中的Lag现象,揭示在分布式系统中消息延迟背后的奥秘。了解Lag的机制对于确保消息的实时性、优化系统性能以及监控分布式系统的稳定性至关重要。我们将深入探讨Lag的定义、影响因素、监控与调优策略,为您呈现Lag的全貌。

todoitbo的博客 1万+

【Kafka】kafka消费组查看lag

[root@1 kafka]# bin/kafka-consumer-groups.sh --list --zookeeper 1.zookeeper1:2181 console-consumer-15370 [root@1 kafka]# bin/kafka-consumer-groups.sh --zookeeper 1.zookeeper1:2181 --group console-consumer-15370 --describe GROUP TO

九师兄 4049

kafka lag

kafka flink lag

qq_36838962的博客 4506

Kafka ConsumerFetcherManager的最大滞后指标(MaxLag)及其在服务器中的应用

在Kafka中,一个主题可以被分为多个分区,每个分区可以由一个消费者组内的一个消费者进行消费。通过监控每个消费者的MaxLag,Kafka可以根据消费者的处理能力动态地重新分配分区,以使每个消费者处理的分区数相对均衡,从而提高整体的消费性能。在ConsumerFetcherManager中,最大滞后指标(MaxLag)起着重要的作用,它用于衡量消费者与生产者之间的数据滞后情况,进而影响消费者的数据获取速度和处理能力。MaxLag的定义是消费者在处理数据时,当前消费的偏移量与最新可用消息的偏移量之间的差异。

XhClojure的博客 338

CMake安装grpc生成gRPCTargets.cmake文件

以下是安装语句: cd grpc_folder git submodule update --init cmake .. make -j 4 sudo make install 然而编写依赖gRPC的程序,发现无法调用gRPC的CMake文件,错误提示如下所示: include could not find load file: /usr/local/lib/cmake/g...

2331

Kafka的Lag计算误区及正确实现

原 Kafka的Lag计算误区及正确实现https://blog.youkuaiyun.com/u013256816/article/details/79955578版权声明:本文为博主原创文章,未经博主朱小厮允许不得转载。 https://blog.youkuaiyun.com/u013256816/article/details/79955578 欢迎支持笔者新作:《深入理解Kafka:核心设计与实践原理》和《Rab...

rede 901

STM32使用内部RC振荡器作为系统时钟开发项目--内晶振启动模板工程

STM32使用内部RC振荡器时,OSC32_IN,OSC32_OUT接法: 1)对于100脚或144脚的产品,OSC_IN应接地,OSC_OUT应悬空。 2)对于少于100脚的产品,有2种接法:    2.1)OSC_IN和OSC_OUT分别通过10K电阻接地。此方法可提高EMC性能。    2.2)分别重映射OSC_IN和OSC_OUT至PD0和PD1,再配置PD0和PD1为推挽输出

overflyme的博客 1万+

kafka中topic默认属性_分享:Kafka 的 Lag 计算误区及正确实现

前言消息堆积是消息中间件的一大特色,消息中间件的流量削峰、冗余存储等功能正是得益于消息中间件的消息堆积能力。然而消息堆积其实是一把亦正亦邪的双刃剑,如果应用场合不恰当反而会对上下游的业务造成不必要的麻烦,比如消息堆积势必会影响上下游整个调用链的时效性,有些中间件如RabbitMQ在发生消息堆积时在某些情况下还会影响自身的性能。对于Kafka而言,虽然消息堆积不会对其自身性能带来多大的困扰,但难免不...

weixin_35156503的博客 918

GD32模拟IIC读写DVC1124

GD32模拟IIC读写集澈AFE芯片DVC1124

ponyma_的博客 1227

Zabbix华为交换机光衰告警

zabbix使用自动发现监控huawei网络设备光衰

qq_31651649的博客 4530

kafka中topic默认属性_Kafka 的 Lag 计算误区及正确实现

作者:朱小厮原文:https://blog.youkuaiyun.com/u013256816/article/details/79955578前言消息堆积是消息中间件的一大特色,消息中间件的流量削峰、冗余存储等功能正是得益于消息中间件的消息堆积能力。然而消息堆积其实是一把亦正亦邪的双刃剑,如果应用场合不恰当反而会对上下游的业务造成不必要的麻烦,比如消息堆积势必会影响上下游整个调用链的时效性,有些...

weixin_31584817的博客 693

SmsForwarder v6.4.0 + Flask API 实战:5步搭建手机验证码自动化接收服务

本文详细介绍了如何利用SmsForwarder v6.4.0和Flask API构建企业级验证码自动化处理系统。通过5个关键步骤,包括系统架构设计、Android端配置、Flask服务端实现、企业级部署方案以及实战应用场景扩展,帮助开发者高效处理短信验证码,提升自动化测试和数据采集的工作效率。

weixin_30292745的博客 394

Kafka 的 Lag消费滞后量计算与监控全解析

Kafka消费滞后量(Lag)是衡量消费者处理能力与消息生产速度差距的关键指标。本文深入解析Lag的计算误区,指出应使用高水位(HW)而非日志末端位移(LEO)来计算真实可消费的滞后量,并提供了多种监控方案:命令行工具、AdminClient API和JMX监控。文章还给出生产环境最佳实践,包括分层阈值设置、智能告警策略和性能优化建议(如多线程消费模式)。通过正确理解Lag计算原理和采取有效监控措施,可预防消息堆积问题,确保系统稳定运行。

油墨香^-^的博客 733

Workbench下列车转向架随机振动疲劳分析

结果中添加功率谱响应工具(Response PSD Tool),可以查看几何体以及远程点上的功率谱密度,如下图11所示,这里查看几何体上某一硬点的加速度功率谱密度响应曲线,如下图12所示。结果中添加疲劳工具(Fatigue Tool),查看列车转向架的疲劳寿命情况,这里采用窄带的寿命假设理论,曝光时间为1s指明计算出的疲劳寿命的基本单位是秒,寿命结果如下图14所示,可以看到最大寿命为1e35s,最小寿命为2.3542e18s,注意单位制,可再次基础上将其转换为小时或天。频域上的统计计算,软件很快计算完成。

ansysxuexizhe的博客 2605

【ComfyUI】FluxKontext 人物服装平铺重构

本文介绍了一个基于ComfyUI的高保真服装语义提取工作流,利用FluxKontext模型实现人物服装结构的精准抽离与平铺展示。工作流包含图像输入、潜空间处理、语义引导和生成输出四个阶段,通过Flux_Kontext_dev_fp8主模型、双CLIP文本编码和VAE转换等核心组件,配合FluxKontextImageScale、ReferenceLatent等节点完成服装结构的稳定提取。流程中CLIPTextEncode负责语义解析,FluxGuidance强化引导力度,KSampler执行最终生成,最终输

Mr数据杨 959

Kafka LAG监控与优化:从原理到实战

本文深入解析Kafka LAG监控与优化,从核心原理到实战技巧全面覆盖。详细讲解消费延迟(LAG)的计算方法、消费者偏移量提交机制,并提供命令行监控、Prometheus+Grafana高级监控方案及典型问题排查手册,帮助开发者有效优化Kafka消费性能。

sony5的博客 919

配置 SAP Web Dispatcher 的实战指南:打通 SAP Fiori、SAP Gateway 与前端系统的关键一跳

SAP Web Dispatcher 在 Fiori 架构中扮演关键角色,作为统一入口处理 HTTPS 请求、实现安全代理和流量分发。它将分散在不同系统的访问路径统一收口,解决浏览器同源策略限制,集中管理 HTTPS 终止和客户端信息传递。典型配置中,Web Dispatcher 监听 443 端口,根据路径将 OData 请求转发至 Gateway 系统,静态资源请求送至前端服务器。SSL 相关配置(如 PSE 文件)确保安全通信,而路由规则(wdisp/system_xx)决定请求转发目标。实施时需注意

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 105

再看 Kafka Lag

在《Kafka的Lag计算误区及正确实现》一文中提及了kafka.admin.ConsumerGroupCommand.PartitionAssignmentState无法被外部访问,故要将PartitionAssignmentState前的protected修饰符去掉 可以直接将describeGroup返回的结果转换成JSON然后传至监控页面(supported by YANGliiN oba...

weixin_33912638的博客 158

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

再看Kafka Lag

在《Kafka的Lag计算误区及正确实现》一文中提及了kafka.admin.ConsumerGroupCommand.PartitionAssignmentState无法被外部访问,故要么将PartitionAssignmentState前的protected修饰符去掉,要么像《 如何获取Kafka的消费者详情》和《集群管理工具KafkaAdminClient——改造》这两篇这样来实现,但是真的...

朱小厮的博客 6884

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

上一篇: 如何获取 Kafka 的消费者详情? —— 从 Scala 到 Java 的切换
下一篇: RabbitMQ消息可靠性分析
Java技术那些事儿
博客等级 码龄5年 2306粉丝 2584原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值