版权声明:本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。期待加入IOT时代最具战斗力的团队。QQ邮箱地址:[email protected],如有任何学术交流,可随时联系。
1 掉下来一个可用性
- 可用性反映了kafka集群应对崩溃的能力,调优可用性就是为了让Kafka更快的从崩溃中恢复过来。
2 Topic角度看问题
- Controller就是broker,主要负责副本分配方案和分区上线的工作(根据副本的分配方案)。
- 副本状态机
- 分区状态机
- 注意Topic的分区数越多,一旦分区的leader副本所在broker发生崩溃,就需要进行leader的选举,虽然Leader的选举时间很短,大概几毫秒,但是Controller处理请求时单线程的,controller通过Zookeeper可实时侦测broker状态。一旦有broker挂掉了,controller可立即感知并为受影响分区选举新的leader,但是在新的分配方案出来后,发布到各个broker进行元数据更新就要浪费网络I/O了。
- 建议分区不要过大,可能会影响可用性。
3 Producer角度看问题
- 首推参数是acks,当acks设置为all时,broker端参数min.insync.replicas的效果会影响Producer端的可用性。该参数越大,kafka会强制进行越多的follower副本同步写入日志,当出现ISR缩减到min.insync.replicas值时,producer会停止对特定分区发送消息,从而影响了可用性。
- 版权声明:本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。期待加入IOT时代最具战斗力的团队。QQ邮箱地址:[email protected],如有任何学术交流,可随时联系。
4 Broker角度看问题
- Broker端高可用性直接的表现形式就是broker崩溃,崩溃之后leader选举有两种:1:从ISR中选择。2:通过unclean.leader.election.enable值决定是否从ISR中选择。第二种情况会出现数据丢失的风险。
- 另一个参数是broker崩溃恢复调优,即num.recovery.threads.per.data.dir。场景是这样的,当broker从崩溃中重启恢复后,broker会扫描并加载底层的分区数据执行清理和与其他broker保持同步。这一工程被称为日志加载和日志恢复。默认情况下是单线程的。假设某个Broker的log.dirs配置了10个日志目录,那么单线程可能就吭哧吭哧扫描加载,太慢了。实际使用中,建议配置为日志的log.dirs磁盘数量。
5 Consumer角度看问题
-
对于Consumer而言,高可用性主要是基于组管理的consumer group来体现的,当group下某个或某些consumer实例“挂了”,group的coordinator能够自动检测出这种崩溃并及时的开启rebalance,进而将崩溃的消费分区分配到其他存活的consumer上。
-
consumer端参数session.timeout.ms就是定义了能检测出failure的时间间隔。若要实现高可用,必须设置较低的值,比如5-10秒。一旦超过该值,就会开启新一轮的reblance。
-
消息处理时间参数很牛,max.poll.interval.ms,参数设置了consumer实例所需要的消息处理时间,一旦超过该值,就是高负荷状态,此时consumer将停止发送心跳,并告知coordinator要离开group。消费者在创建时会有一个属性max.poll.interval.ms,
该属性意思为kafka消费者在每一轮poll()调用之间的最大延迟,消费者在获取更多记录之前可以空闲的时间量的上限。如果此超时时间期满之前poll()没有被再次调用,则消费者被视为失败,并且分组将重新平衡,以便将分区重新分配给别的成员 -
hearbeat.interval.ms 当coordinator决定开启新一轮的reblance时,他会把这个决定以REBALANCE_IN_PROCESS异常的形式塞进consumer心跳的请求响应中,这样就可以飞快的感知到新的分区分配方案。
-
kafka调优经典的独白,哈哈哈哈:
上线两个月都没有问题,为什么最近突然出现问题了。我想肯定是业务系统有什么动作,我就去问了一个下, 果然头一天风控系统kafka挂掉了,并进行了数据重推,导致了数据阻塞。但是我又想即使阻塞了也会慢慢消费掉啊,不应 该报错呀。后来我看了一下kafka官网上的参数介绍,发现max.poll.records默认是2147483647 (0.10.0.1版本),也就是kafka里面有多少poll多少,如果消费者拿到的这些数据在制定时间内消费不完,就会手动提交 失败,数据就会回滚到kafka中,会发生重复消费的情况。如此循环,数据就会越堆越多。后来咨询了公司的kafka大神,他 说我的kafka版本跟他的集群版本不一样让我升级kafka版本。于是我就升级到了0.10.2.1,查阅官网发现这个版本的max.po ll.records默认是500,可能kafka开发团队也意识到了这个问题。并且这个版本多了一个max.poll.interval.ms这个参数, 默认是300s。这个参数的大概意思就是kafka消费者在一次poll内,业务处理时间不能超过这个时间。后来升级了kafka版本 ,把max.poll.records改成了50个之后,上了一次线,准备观察一下。上完线已经晚上9点了,于是就打卡回家了,明天看 结果。第二天早起满心欢喜准备看结果,以为会解决这个问题,谁曾想还是堆积。我的天,思来想去,也想不出哪里有问题 。于是就把处理各个业务的代码前后执行时间打印出来看一下,添加代码,提交上线。然后观察结果,发现大部分时间都用 在数据库IO上了,并且执行时间很慢,大部分都是2s。于是想可能刚上线的时候数据量比较小,查询比较快,现在数据量大 了,就比较慢了。当时脑子里第一想法就是看了一下常用查询字段有没有添加索引,一看没有,然后马上添加索引。加完索 引观察了一下,处理速度提高了好几倍。虽然单条业务处理的快乐, 但是堆积还存在,后来发现,业务系统大概1s推送3、4条数据,但是我kafka现在是单线程消费,速度大概也是这么多。再 加上之前的堆积,所以消费还是很慢。于是业务改成多线程消费,利用线程池,开启了10个线程,上线观察。几分钟就消费 完了。大功告成,此时此刻,心里舒坦了好多。不容易呀!
6 参数清单
Broker端
- 避免过多分区
- 设置unclean.leader.election.enable=true(为了可用性,数据丢失不考虑)
- 设置min.insync.replicas=1(减轻同步压力)
- 设置num.recovery.threads.per.data.dir=broker 日志的log.dirs磁盘数
Producer端
- 设置acks=1,设置为all时,遵循min.insync.replicas=1
consumer端
- 设置session.timeout.ms为较低的值,比如100000
- 设置max.poll.interval.ms消息平均处理时间,可适当调大。
- 设置max.poll.records和max.partition.fetch.bytes减少消息处理总时长,避免频繁的rebalance。
- 版权声明:本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。期待加入IOT时代最具战斗力的团队。QQ邮箱地址:[email protected],如有任何学术交流,可随时联系。
7 总结
num.recovery.threads.per.data.dir以及max.partition.fetch.bytes以及max.poll.records重点关注一下,很有意思的选手。
秦凯新 于深圳 201812042237
版权声明:本套技术专栏是作者(秦凯新)平时工作的总结和升华,通过从真实商业环境抽取案例进行总结和分享,并给出商业应用的调优建议和集群环境容量规划等内容,请持续关注本套博客。期待加入IOT时代最具战斗力的团队。QQ邮箱地址:[email protected],如有任何学术交流,可随时联系。