🗒️kafka的broker不均衡和leader不均衡处理
2023-1-2
| 2023-4-10
0  |  0 分钟
type
status
date
slug
summary
tags
category
icon
password

1.背景

集群是三台节点,id分别是1 2 3,kafka版本2.11-2.1.1。
由于某些原因需要重启一台节点,确认__consumer_offsets副本为3后,重启。虽然业务正常,但__consumer_offsets的describe结果不如意,而且三台节点的CPU MEM负载曲线是发散状(高的越高、低的越低),明显三台节点的不平衡加大了。 平衡是相对概念,三台节点即使配置一致,负载还是会有差别。
  • Leader节点没有broker2
./kafka-topics.sh --describe --zookeeper 127.0.0.1:2181|grep __consumer_offsets Topic:__consumer_offsets PartitionCount:50 ReplicationFactor:3 Configs:segment.bytes=104857600,cleanup.policy=compact,compression.type=producer Topic: __consumer_offsets Partition: 0 Leader: 3 Replicas: 1,2,3 Isr: 3,1,2 Topic: __consumer_offsets Partition: 1 Leader: 3 Replicas: 2,3,1 Isr: 3,1,2 Topic: __consumer_offsets Partition: 2 Leader: 1 Replicas: 3,1,2 Isr: 3,1,2 Topic: __consumer_offsets Partition: 3 Leader: 3 Replicas: 1,3,2 Isr: 3,1,2 ---------------------- Topic: __consumer_offsets Partition: 48 Leader: 3 Replicas: 1,2,3 Isr: 3,1,2 Topic: __consumer_offsets Partition: 49 Leader: 3 Replicas: 2,3,1 Isr: 3,1,2,
  • 查看consumer groups 没有broker2,其实和1是同一个问题。

2. 解决办法

2.1 弯路:broker不均衡

简而言之,把现状按照扩容新节点来处理,用topics-to-move.json这种topic迁移的办法,将topic均衡到新的节点,但是没有任何效果。
事后反思,现状的三台节点都有副本,只是一台没有leader角色,不符合broker不均衡的情况。broker不均衡应该是topic只出现在老的broker里。
broker不均衡在web管理页面看到的是Broker Spread指标不为100%,100%才是均衡。
notion image

2.2 正确思路:leader均衡

leader不均衡在在web管理页面看到的是Broker Leader Skewed指标不为0%,0%才是均衡。由于leader才是读写压力最大的角色,故leader不均衡导致部分节点压力过大。
notion image
按topic的partition顺序写出new_election.json,
cat new_election.json { "partitions": [ {"topic": "yourtopic", "partition": 0}, {"topic": "yourtopic", "partition": 1}, {"topic": "yourtopic", "partition": 2} ] } bin/kafka-preferred-replica-election.sh --zookeeper 127.0.0.1:2181 --path-to-json-file new_election.json
不建议在生产开启auto.leader.rebalance.enable=true,自动重新选举会干扰业务。 手动创建JSON文件有点蛋疼,特别是你的topic partition很多的情况下,下面是一个参考脚本,当然前提是你拿到了leader不均衡的topic信息。
cat create_elect.sh #!/bin/sh topic=yourtopic out=elect_${topic}.json num=49 cat >$out <<\\EOF { "partitions": [ ] } EOF #顺序写入partition for i in `seq 0 $num`;do sed -i "/\\]/i\\ {\\"topic\\": \\"$topic\\", \\"partition\\": $i}," $out done sed -i "s/: $num},/: $num}/" $out #执行选举,默认静默执行。如果调试,去掉>/dev/null 2>&1 bin/kafka-preferred-replica-election.sh --zookeeper 127.0.0.1:2181 --path-to-json-file $out >/dev/null 2>&1 #查看topic状态 bin/kafka-topics.sh --describe --zookeeper 127.0.0.1|grep -w $topic

3.发散猜想

提交到topic的时候,key是当前消费者所处的消费组ID+topic+分区号,value就是当前offset的值,那么kafka会把这个消息发送到哪个分区呢,是由以下公式决定的:hash(consumer group id) % __consumer_offsets主题的分区数(默认50),consumer每次消费前都会从这里获取offset值;
  • consumer group消费前会获取__consumer_offsets分区的offset值;
  • consumer group消费后会向__consumer_offsets分区提交offset值。 如果一个group订阅过多的topic,理论上没有充分利用__consumer_offsets的50个分区,都集中在一个分区了,人为制造读写瓶颈。另外,如果consumer发生变化,会导致rebalence,那这个group下面所有的消费实例无法消费。
以上
 
技术
  • 中间件
  • Prometheus pushgateway采集shell脚本获取的指标curl钉钉告警${content}文本含空格/换行的问题
    目录