KafkaTemplate发送请求抛出NotLeaderOrFollowerException的排查建议
异常信息
根因:org.apache.kafka.common.errors.NotLeaderOrFollowerException: 对于仅发送给Leader的请求,该错误表示当前Broker不是目标分区的Leader;对于发送给任意副本的请求,该错误表示当前Broker不是目标分区的副本。
生产者配置
p.setProperty(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092,localhost:9093,localhost:9094"); p.setProperty(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); p.setProperty(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); p.setProperty(ProducerConfig.ACKS_CONFIG, ProducerAckMode.ALL.getType()); p.setProperty(ProducerConfig.ENABLE_IDEMPOTENCE_CONFIG, "true"); p.setProperty(ProducerConfig.RETRIES_CONFIG, "10");
Topic配置
TopicBuilder.name("test-topic-10") .partitions(3) .replicas(3) .build()
Broker配置
共部署3个Broker,配置如下:
spring.kafka.bootstrap-servers=localhost:9092,localhost:9093,localhost:9094
消息发送代码
SendResult<String, Object> result = arilKafkaTemplate.send("test-topic-10", UUID.randomUUID().toString(), "data").get(); RecordMetadata metadata = result.getRecordMetadata();
持续异常日志
在发送到分区test-topic-10-1的生产请求中收到无效元数据错误,原因是org.apache.kafka.common.errors.NotLeaderOrFollowerException: 对于仅发送给Leader的请求,该错误表示当前Broker不是目标分区的Leader;对于发送给任意副本的请求,该错误表示当前Broker不是目标分区的副本。即将请求更新元数据 2024-03-11T20:35:28.207+03:00 WARN 16076 --- [ad | producer-2] o.a.k.clients.producer.internals.Sender : [Producer clientId=producer-2] 收到关联ID为20的生产响应错误,正在重试(剩余1次尝试)。错误:NOT_LEADER_OR_FOLLOWER
异常核心原因
结合配置与日志,该异常的触发主要有以下几种可能:
Leader副本频繁切换
你的Topic配置了3个副本,当原Leader Broker出现故障、网络波动或负载过高时,Kafka会触发分区Leader选举。但生产者本地缓存的元数据未及时更新,仍向旧Leader发送请求,从而抛出异常。日志中"即将请求更新元数据"的提示也印证了这一点——如果Leader切换频率超过元数据更新速度,就会持续出现重试失败的情况。Broker集群状态不稳定
3节点集群中,若某台Broker离线、心跳超时或节点间通信异常,会导致分区副本同步状态异常。比如部分副本被标记为非同步副本,无法参与Leader选举,或者集群元数据不一致,导致生产者获取的Leader信息不准确。生产者元数据更新滞后
生产者收到错误后会触发元数据更新,但如果网络延迟过高或更新请求阻塞,重试窗口内可能仍使用过期元数据发送请求。虽然你设置了10次重试,但如果Leader切换过于频繁,重试机制也无法跟上元数据的变化速度。分区副本分配异常
虽然Topic配置了3个副本,但实际集群中可能存在副本分配错误——比如某个分区的副本未正确分配到3台Broker上,导致部分Broker不是该分区的副本。当生产者误将请求发送到这些Broker时,就会触发"不是分区副本"的错误。可以通过kafka-topics.sh --describe --topic test-topic-10 --bootstrap-server localhost:9092命令检查分区副本的实际分配状态。
内容的提问来源于stack exchange,提问作者Sha

