前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >从Kafka的故障引发的思考

从Kafka的故障引发的思考

作者头像
richard.xia_志培
发布2022-06-14 14:37:13
4530
发布2022-06-14 14:37:13
举报
文章被收录于专栏:PT运维技术

背景介绍:

过去的Kafka的一起故障,虽然这起规则没有引起业务上损失,但是故障后的复盘值得深思。故障表现出来的现象和真实原因相差甚远。(不要根据现象就轻易下结论)

----------------------------------------------------------------------

故障现象

应用是基于tomcat的,应用通过部署系统发布到灰度环境后,测试没有问题后,接着应用运维将代码包部署到其中一个机房(承载流量较小),QA同学再次测试新功能,发现新功能异常(未发现新功能) 。QA同学将相关信息反馈给开发同学后,开发同学觉得应用运维并没有发布新代码,或者线上运行的是老的代码。因此问题从开发转到运维侧,应用运维观察应用日志和代码的MD5, 没有发现什么问题,开发侧,运维侧僵持地坚持自己的判断。于是介入进去,定位问题到底出现在哪个环节。多年职业经验的直觉告诉我,这个问题不简单,我们看到仅仅非常表面的现象(例如:森林地表落叶层下的盘根错节根本就看不到)。

----------------------------------------------------------------------

原因分析

于是收集各方的反馈的信息:

1.1 运维侧:A机房灰度分组没有问题,机房A的其他的分组有问题,灰度分组的war包和其他分组的war包的MD5一致。应用日志无异常报错 。

1.2 测试QA:A机房灰度分组下代码新功能可以使用,A机房其他分组新功能无法使用。

1.3 开发侧:同样代码在不同的分组表现不一样,所以是运维侧代码发布问题,环境问题导致 。(从现象来看,确实如此,无言以对)

由于新功能不能使用并不影响先前的功能,并且A机房的流量有限, 因此没有着急回滚。

最开始怀疑进程没有重启,观察进程启动的时间后,排除掉,接着怀疑tomcat的缓存,strace 跟踪后,排除掉,对比灰度分组和正常分组下的tomcat启动日志,逐行对比后,并没有发现明显差异。开发同学反馈:之前发布出现过一次,让应用运维重启后就解决了。通过发布任务的时间追溯,发现在XX月11日,就开始存在这种现象(这种现象维持了一段时间)。开始查看11日以及之前的应用日志,发现9日存在大量异常的日志,跟kafka相关。跟开发同学沟通后,新功能跟kafka的某个topic相关(消费者需要消费该topic)。到此,问题范围已经大大缩小了。kafka的大部分topic都是正常,仅部分topic工作异常。

联系公有云kafka的研发,将kafka相关日志拿了过来,仔细分析kafka日志和应用端的日志后发现:

kafka 在9日凌晨 发生网络分区,broker3以前是controller, broker1和broker2在一个分区,broker3在另外的一个分区,此刻broker1被选举为controller, ISR(1,2), broker3 此刻无感知。zookeeper seesion timeout为4000ms+(zk tick time 为:2000ms)。几分钟后,broker3在未恢复的情况,再次发生broker1网络故障,10秒后故障恢复。(典型的连续故障场景,一般的分布式组件是扛不住的)。联系公有云后,9日凌晨有网络变更,但他们评估不影响到业务方,因此没有告知使用方 (无力吐槽)。

事故的时间起点可以大体上对得上,但还需要深入分析。

----------------------------------------------------------------------

Kafka的消费过程深入分析:

消费者要消费消息,必须依赖Coordinator。(Coordinator 用于管理 Consumer Group 中各个成员,负责消费 offset 位移管理和 Consumer Rebalance)。

Consumer 在消费时必须先确认 Consumer Group 对应的 Coordinator,随后才能 join Group,获取对应的 topic partition 进行消费。

那如何确定 Consumer Group 的 Coordinator 呢?分2个阶段:

第一阶段:

一个 Consumer Group 对应一个__consumers_offsets topic的分区,首先先计算 Consumer Group 对应的__consumers_offsets 的分区,计算公式如下:

代码语言:javascript
复制
__consumers_offsets partition# = Math.abs(groupId.hashCode() % groupMetadataTopicPartitionCount

其中 groupMetadataTopicPartitionCount 由 offsets.topic.num.partitions 指定。

第二阶段:

阶段一 中计算的该 partition 的 leader 所在的 broker 就是被选定的 Coordinator。该案例中,连续故障的情况下,造成__consumers_offsets的部分分区ISR(3,1,2)变成ISR(2),从而Coordinator无法选出Leader,这就直接导致了消费卡死。

回到故障表现出来现象中:

由于程序端的consumer 每次启动都会生成一个新的消费者group, 从而hash到__consumers_offsets的不同分区(50个分区), 只要不要落到异常分区( 17个分区无法选出leader), 程序端就可以正常消费,新功能就正常, 因此重新部署代码都会导致应用重启,应用初始化会使用新的consumer group, 小概率性地分配到__consumers_offsets的无Leader分区的Coordinator, 因此会出现灰度分组和正常分组 一个正常,一个异常。因此从表象上看,重启可以大概率地解决问题。

----------------------------------------------------------------------

事后总结:

1. 出现异常,为什么业务日志/应用日志无任何报错?

这个里面分2个阶段:

第一阶段:

在网络分区的时候,应用端确实产生异常的日志, 但由于日志规范推动乏力(运维侧不能依靠exception, error 类型的关键字产生告警),运维侧只能将已知的错误日志纳入监控,例如kafka属于新增错误类型, 所以即使有异常日志但没有告警。

第二阶段:

应用程序的consummer连接到Coordinator, coordinator无法选出leader, 但应用层未捕获到任何异常,导致问题无法发现(kafka sdk每个开发团队使用都不一样)。

2. 为何不启用APM?

由于采用的开源pinpoint解决方案,存在较大的性能损耗,核心链路并没有开启。

3. 为什么2周后才发现这个问题?

由于Kafka使用是公有云Pass服务,使用的监控是pass提供的监控监控,pass层kafka无该层面的监控,pass端提供的kafka监控无任何异常, 导致使用方无法窥测。

----------------------------------------------------------------------

总体上来看,故障由多个因素共同影响下爆发出来。虽然故障影响较小,但反馈的问题不少:

运维侧:

1.公有云Pass层Kafka监控粒度较为粗糙,需要使用方补齐底层监控或者自建。

开发侧:

1.日志标准化建设:(日志等级/格式标准化 统一标准)

2.组件的接入层标准化接入 (公司层面统一标准),禁止自动创建消费者组

流程层面:

1.完善第三方变更通知机制

2.应用运维在确保操作无误后,发现异常情况需要记录反馈。

标准化的建设是所有技术人员逐步规范化的过程(不分开发,运维), 否则技术债务到了一定阶段会反噬业务。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 PT运维技术 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档