Kafka集群单节点故障时Scala消费者无法接收消息求助
先看你贴的日志,里面藏着关键线索:
Partition(topic = SOMETOPIC, partition = 0, leader = none, replicas = [1,], isr = [], Partition(topic = SOMETOPIC, partition = 1, leader = none, replicas = [2,], isr = []
这说明SOMETOPIC的分区0和1只在故障的那两个broker上有副本,没有其他备份。所以当这俩broker挂了之后,这两个分区根本选不出leader,直接处于不可用状态。而kafka-console-consumer能正常跑,本质是它的默认配置和你自己写的Scala Consumer不一样,不是集群本身的问题。
可能的原因和对应的解决办法
1. 业务主题的复制因子没设对(只配了内部偏移量主题,忘了业务主题)
你已经把offsets.topic.replication.factor设成3了,这个是对Kafka内部存储消费偏移量的主题生效的,但你的业务主题SOMETOPIC大概率用了默认的复制因子1。这就导致一旦存某个分区副本的broker挂了,这个分区就彻底歇菜了。
怎么验证和修复:
- 先查一下SOMETOPIC的具体配置:
看每个分区的kafka-topics.sh --describe --topic SOMETOPIC --bootstrap-server <你的broker地址>:9092Replicas列,如果只有单个broker ID,那就是复制因子为1没跑了。 - 给SOMETOPIC加副本(得先把故障的broker恢复,要是恢复不了,就得手动调整分区副本分配):
- 先写个副本分配的JSON文件,比如叫
increase-replica.json:{"version":1, "partitions":[ {"topic":"SOMETOPIC","partition":0,"replicas":[0,1,2]}, {"topic":"SOMETOPIC","partition":1,"replicas":[0,1,2]}, {"topic":"SOMETOPIC","partition":2,"replicas":[0,1,2]} ]} - 执行扩容命令:
kafka-reassign-partitions.sh --zookeeper <你的ZK地址>:2181 --reassignment-json-file increase-replica.json --execute - 验证一下扩容是否成功:
kafka-reassign-partitions.sh --zookeeper <你的ZK地址>:2181 --reassignment-json-file increase-replica.json --verify
- 先写个副本分配的JSON文件,比如叫
2. Scala Consumer的配置和控制台消费者不一样
kafka-console-consumer默认带了一些“容错”配置,比如跳过不可用分区、自动重置偏移量,而你的Scala Consumer可能没配这些,导致卡在了获取不可用分区的元数据上。
关键配置调整:
auto.offset.reset:如果你的Consumer设成了none(旧版本客户端默认可能是这个),那当拿不到偏移量的时候就会卡住;而控制台消费者默认是latest,直接从最新的可用偏移量开始消费,跳过不可用的分区。你可以在Scala代码里加上:props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "latest") // 要是业务需要从头消费就设成"earliest"metadata.max.age.ms:默认是5分钟才刷新一次元数据,改成5秒让Consumer更快感知集群变化:props.put(ConsumerConfig.METADATA_MAX_AGE_CONFIG, "5000")fetch.max.wait.ms:如果等数据的时间太长,也容易卡住,改成最多等1秒就返回:props.put(ConsumerConfig.FETCH_MAX_WAIT_MS_CONFIG, "1000")
3. 客户端版本太老,有兼容性bug
如果你的Scala Consumer用的Kafka客户端版本和集群版本差得比较多,可能在处理broker故障后的元数据更新时存在bug。建议把客户端版本升级到和集群版本接近的(尽量控制在1个大版本以内,比如集群是2.8.x,客户端就用2.7.x到3.0.x之间的)。
临时救急方案(如果没法马上恢复broker或调副本)
要是想先让Scala Consumer跑起来,可以临时改订阅逻辑,只订阅可用的分区(比如日志里的分区2),但这只是权宜之计,最终还是得把业务主题的高可用配置做好,不然下次再出故障还是会卡住。
内容的提问来源于stack exchange,提问作者Igorock

