← 中文资源

简体中文版本

Kafka 生产者 TimeoutException — 批次中的消息过期

排查 Kafka 生产超时:核对主题元数据与 ISR,检查 delivery.timeout.ms 时间预算,调整 acks、linger、重试和 broker 容量。

阅读英文原文

现象

生产者抛出 TimeoutException: Expiring 1 record(s) for orders-0: 30000 ms has passed since batch creation,或 Topic orders not present in metadata after 60000 ms;开发环境正常,压测时超时;生产吞吐骤降但消费 lag 并不高。

诊断

先确认主题与分区领导节点:

kafka-topics.sh --bootstrap-server localhost:9092 --describe --topic orders
kafka-topics.sh --bootstrap-server localhost:9092 \
  --describe --under-replicated-partitions

主题不存在或分区没有 leader 会直接导致元数据超时;若 ISR 小于 min.insync.replicas,acks=all 永远无法成功,磁盘写满的 broker 常表现成这样。再用控制台生产者验证链路:

kafka-console-producer.sh --bootstrap-server localhost:9092 --topic orders \
  --producer-property acks=all --producer-property delivery.timeout.ms=10000

立即报错说明 broker 侧拒绝,一直挂到超时则更像网络不可达、元数据失败或请求队列饱和。最后用 kafka-producer-perf-test.sh 对比平均与最大延迟,判断是否存在 broker 限流或重试放大。

修复

把 delivery.timeout.ms 设为明显大于 linger.ms + request.timeout.ms + 重试退避 的值,低延迟场景降低 linger.ms,保持 acks=all 并修复 ISR;恢复 broker 磁盘与负载,复用单个长生命周期生产者,并开启幂等避免重试重复写入:

acks=all
enable.idempotence=true
linger.ms=20
request.timeout.ms=30000
delivery.timeout.ms=120000

验证

以生产参数重跑 perf test,确认最大延迟低于 delivery.timeout.ms 且过期记录为零;重启一个 broker 时观察 record-error-rate 能回落到 0,under-replicated 分区清空,消费者侧每条订单只出现一次,说明超时重试没有造成重复。