一、当Kafka开始"挑食"时

你有没有遇到过这样的场景:公司食堂打饭时,3号窗口排成长龙,5号窗口却门可罗雀?Kafka集群有时候也会这样"挑食"。明明有10个broker,但总有几个忙得脚不沾地,其他却在"摸鱼"。这种负载不均会导致消息积压、延迟增加,严重时甚至会影响整个系统的稳定性。

举个真实案例:某电商平台在大促期间,订单服务的Kafka消费者突然出现严重延迟。排查发现,80%的分区都集中在3个broker上,而集群共有15个broker。这就好比把1000人的用餐需求都塞进一个小餐厅,不堵才怪。

二、诊断问题的"听诊器"

要解决问题,首先得找到病因。以下是几个实用的诊断命令(基于Kafka 2.8版本):

# 查看所有topic的分区分布情况
bin/kafka-topics.sh --bootstrap-server localhost:9092 --describe

# 示例输出:
# Topic: order-events Partition: 0 Leader: 1 Replicas: 1,2 Isr: 1,2
# Topic: order-events Partition: 1 Leader: 3 Replicas: 3,4 Isr: 3,4
# Topic: payment-events Partition: 0 Leader: 1 Replicas: 1,3 Isr: 1,3

# 查看broker负载情况
bin/kafka-broker-api-versions.sh --bootstrap-server localhost:9092 | grep disk

# 查看消息积压情况
bin/kafka-consumer-groups.sh --bootstrap-server localhost:9092 --group order-group --describe

通过分析这些数据,你可能会发现:

  1. 某些broker承载了过多leader分区
  2. 分区数量在不同broker间分布不均
  3. 磁盘I/O或网络带宽成为瓶颈

三、分区再平衡的"手术方案"

发现问题后,我们需要进行分区再平衡。这里介绍三种常用方法:

3.1 手动重新分配

# 1. 创建reassignment-plan.json
{
  "version": 1,
  "partitions": [
    {"topic": "order-events", "partition": 0, "replicas": [2,3]},
    {"topic": "order-events", "partition": 1, "replicas": [4,5]}
  ]
}

# 2. 执行重新分配
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
  --reassignment-json-file reassignment-plan.json \
  --execute

# 3. 验证进度
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
  --reassignment-json-file reassignment-plan.json \
  --verify

优点:精准控制每个分区的去向 缺点:操作繁琐,容易出错

3.2 使用kafka-reassign-partitions自动生成

# 自动生成平衡方案
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
  --topics-to-move-json-file topics.json \
  --broker-list "1,2,3,4,5" \
  --generate

# topics.json内容:
{"topics": [{"topic": "order-events"}], "version":1}

这种方法会自动计算最优分配方案,适合大规模集群。

3.3 使用Cruise Control

这是LinkedIn开源的自动化运维工具,可以持续监控并自动平衡:

# 启动重新平衡
curl -X POST http://cruise-control-server:9090/kafkacruisecontrol/rebalance \
  -H "Content-Type: application/json" \
  -d '{
    "goals":["RackAwareGoal","ReplicaCapacityGoal","DiskCapacityGoal"],
    "dryRun":false
  }'

四、平衡的艺术与科学

再平衡不是一劳永逸的,需要注意:

  1. 黄金时段:选择业务低峰期操作,避免影响线上服务
  2. 分批操作:大型集群建议每次移动不超过10%的分区
  3. 监控指标
    • 网络吞吐量(特别是跨机架传输)
    • 磁盘I/O等待时间
    • Controller节点的CPU使用率
# 监控再平衡期间的性能指标
watch -n 1 'bin/kafka-run-class.sh kafka.tools.JmxTool \
  --object-name kafka.server:type=BrokerTopicMetrics,name=BytesInPerSec \
  --jmx-url service:jmx:rmi:///jndi/rmi://localhost:9999/jmxrmi'

五、预防胜于治疗

与其事后补救,不如提前预防:

  1. 合理规划分区数:建议每个broker承载100-200个分区
  2. 机架感知配置:防止所有副本都在同一个机架
  3. 定期健康检查:建议每周运行一次平衡检查
# server.properties配置示例
broker.rack=rack1
num.partitions=10
default.replication.factor=3

六、特殊场景处理

6.1 新增broker时的平衡

# 将新增的broker6加入平衡列表
bin/kafka-reassign-partitions.sh --bootstrap-server localhost:9092 \
  --broker-list "1,2,3,4,5,6" \
  --topics-to-move-json-file all-topics.json \
  --generate

6.2 处理"热点"分区

对于特别活跃的分区(如双11的秒杀主题),可以考虑:

  1. 增加该topic的分区数
  2. 单独为该topic配置更高的副本因子
  3. 使用分区级限流
// 生产者端代码示例(Java)
Properties props = new Properties();
props.put("max.in.flight.requests.per.connection", 1); // 降低并发
props.put("linger.ms", 50); // 适当增加批量发送时间

七、总结与最佳实践

经过多次实战,我总结出以下经验:

  1. 平衡是个持续过程,不是一次性任务
  2. 自动化工具能减少人为错误
  3. 平衡前务必备份关键配置
  4. 监控系统比人工检查更可靠
  5. 文档记录每次平衡的参数和效果

最后分享一个真实的成功案例:某社交平台通过定期平衡,将消息延迟从800ms降至200ms,集群资源利用率从"旱的旱死涝的涝死"变成了"雨露均沾"。

记住,Kafka集群就像团队合作,只有合理分工才能发挥最大效能。下次当你发现消费者开始"饿肚子"时,不妨用这些方法给它们重新分配"用餐座位"。