从一个生产上的错误看kafka的消费再均衡问题
问题描述
项目在生产上的一段错误日志如下,
这是一段kafka的错误日志,大概的意思是说,
kafka的服务端在超过了 max.poll.interval.ms 时间内没有收到某个消费者的心跳,认为该消费者已经“挂了”,所以进行了topic的分区所有权“再均衡”。
问题的分析
按照我的个人习惯,遇到类似这样的生产问题,解决之后我会思考下涉及的技术细节并做整理。
如果对问题涉及的技术细节非常的了解,对于定位问题是非常有帮助的。本文就带你深入了解下上面那个错误日志涉及的一些技术细节。
kafka的topic分区
为了提高消息处理的高可用以及便于横向扩展,kafka引入了topic的分区概念。属于同一个消费者群组的消费者可以分担的消费同一个topic不同分区的消息。从而达到分流的作用,可以使消息处理更高效。
如上图示例所示,topic A有三个分区,同时我们有三个属于同一个群组的消费者,这样每个消费者可以负责消费一个分区。大家各自负责自己的分区,系统有条不紊的运行着。
一般情况下,我们通过增加群组里的消费者数量来提高 kafka 的消费能力。不过要注意,不要让消费者的数量超过主题分区的数量,多余的消费者只会被闲置。
心跳机制
kafka 的服务端需要一直监控有哪些消费者在消费,监控的机制是通过消费者不断的发送心跳包实现的。消费者发送心跳有两个途径,一个是轮询(poll,这里不是为了秀英文,注意联系上面的错误日志),一个是消费后提交 offset 。
这两种方式是两个独立的线程,互相不干扰。
只要消费者以正常的时间间隔发送心跳,就被认为是活跃的,说明它还在读取分区里的消息,否则就被认为是已经“死亡”。 这个所谓的正常的时间间隔,就是不能超过 max.poll.interval.ms。
kafka的分区再均衡
消费者通过向服务端发送心跳来维持它们和群组的从属关系以及它们对分区的所有权关系。如果服务端认为某个消费者已经“死亡”,就会触发一次再均衡。如下图所示,
前面说过,群组里的消费者共同读取主题的分区。
比如有一个新的消费者加入群组,它读取的是原本由其他消费者读取的消息。当一个消费者被关闭或发生崩溃时,它就离开群组,原本由它读取的分区将由群组里的其他消费者来读取。
分区的所有权从一个消费者转移到另一个消费者,这样的行为被称为再均衡。
再均衡有什么意义吗?
当然,有了再均衡,我们可以放心的添加或者移除某个消费者,而不用担心消息的丢失。
解决问题
了解了相关的技术细节后,我们可以顺藤摸瓜,慢慢排查问题。基于前面的分析,我给出几个排查的方向:
- 看看某个消费者的服务是否已经挂了?
- 如果服务正常运行,服务所在的节点是否存在内存或者CPU占满的情况,导致消费者无法及时的发送心跳等。我遇到的情况就是后者引起的。后来解决了内存占用满的问题后,kafka的错误就不存在了。
- 根据自己实际的业务情况,考虑增加 max.poll.interval.ms 的值。
参考:
- 《kafka权威指南》
- zephir-(10)内置函数
- zephir-(9)类和对象2
- 深度学习中的动手实践:在CIFAR-10上进行图像分类
- 数据库中间件 MyCAT源码分析 —— XA分布式事务
- [喵咪Golang(1)]Go语言开篇
- phalcon-进阶篇2(拦截器)
- 【死磕Java并发】—–深入分析synchronized的实现原理
- phalcon-进阶篇1(过滤与清理)
- phalcon-入门篇9(view层基础使用)
- PhalApi视频教程
- 【学术】一文搞懂自编码器及其用途(含代码示例)
- PhalApi-Zip--压缩文件处理类
- PhalApi-Xhprof -- Facebook开源的轻量级PHP性能分析工具
- OpenAI发布8个模拟机器人环境以及一种HER实现,以训练实体机器人模型
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- via the 'serverTimezone' configuration property
- 急速 debug 实战一(浏览器-基础篇)
- MongoDB系列一: Replica Set 集群搭建实战
- 函数式编程看React Hooks(一)简单React Hooks实现
- 函数式编程看React Hooks(二)事件绑定副作用深度剖析
- Vue 开发必须知道的 36 个技巧【近1W字】
- 吃透 Vue 项目开发实践|16个方面深入前端工程化开发技巧《上》
- 【漫游Github】无编译/无服务器,实现浏览器的 CommonJS 模块化
- 《秋风日常第一期》白板协作工具 LeanBoard
- 《秋风日常第二期》一个快速找出待SEO图片的技巧
- 《模块化系列》snowpack,提高10倍打包速度。
- 《秋风日常第三期》11个前端开发者必备的网站
- 专为程序员定制的垃圾清理工具(Node Cli实现)
- CodePen vue SFC 、flutter 在线玩耍来袭
- [重拾CSS]一道面试题来看伪元素、包含块和高度坍塌