首页/数据/数据工程与 ETL 速查/Kafka 生产者工作流程
Kafka64 条

Kafka 生产者工作流程

生产者发送一条消息经历:序列化 → 分区器选择分区 → 进入累加器等待成批 → 发送到分区 Leader → 按 acks 等待确认,失败按重试策略重发。

一条消息的发送路径

生产者发送一条消息依次经历:序列化 key 与 value、分区器决定写入哪个分区、进入累加器缓冲成批、由后台发送线程发往该分区的 Leader、按 acks 配置等待确认,失败则按重试策略重发。理解这条路径,才能判断延迟与丢数分别出现在哪一环。

批量与延迟的取舍

累加器把短时间内的多条消息凑成一个批次发送,批次越大,网络与磁盘的利用率越高、吞吐越好,但单条消息的等待时间也越长。这是生产者最重要的调优取舍:需要吞吐就调大批次并允许短暂等待,需要低延迟就让消息尽快发出。

基本信息

关键组件序列化器、分区器、记录累加器(缓冲批次)、发送线程
连接方式只需指定两到三个 Broker 地址获取元数据,无需列全部节点
幂等开启后同一生产者会话内重试不会产生重复
顺序分区内有序;开启重试时需注意并发请求数对顺序的影响
主要调优点批次大小、等待时间、确认级别与重试上限

关键参数读法

参数作用影响
bootstrap.servers初始连接的 Broker 地址写两三个即可,写错会导致元数据获取失败
acks写入确认级别越高越可靠,延迟与失败率越高
enable.idempotence幂等写入,重试不重复与 acks=all 搭配使用,生产推荐开启
linger.ms发送前额外等待时间,用于凑批调大提升吞吐,增加单条延迟
batch.size单批最大字节数过小会导致批次装不满,吞吐上不去
delivery.timeout.ms从发送到最终失败的总时限包含重试时间,设置过大会让发送长时间阻塞

典型使用场景

  • 高吞吐日志采集:调大批次与等待时间,换取更高吞吐
  • 低延迟告警事件:让消息尽快发出,容忍批次变小
  • 账务类事件:acks=all 加幂等,宁可写入失败也不丢不重
  • CDC 输出:变更事件需要严格保序,按主键分区并谨慎设置并发
  • 压测评估:使用与生产一致的序列化方式与确认级别,否则结论不可用

生产者核心配置

生产者核心配置
bootstrap.servers=kafka1:9092,kafka2:9092
key.serializer=org.apache.kafka.common.serialization.StringSerializer
value.serializer=org.apache.kafka.common.serialization.StringSerializer
acks=all                                  # 等 ISR 全部确认
enable.idempotence=true                   # 重试不产生重复
retries=2147483647                        # 与幂等配合时的常见设置
batch.size=32768                          # 单批 32KB,写大一些减少请求数
max.in.flight.requests.per.connection=5   # 单连接未确认请求数上限

发送与回调(Java)

发送与回调(Java)
ProducerRecord<String, String> record =
    new ProducerRecord<>("orders", order.getOrderId(), json);
// 指定 key 后,同一订单的变更固定进入同一分区,保证局部有序
producer.send(record, (metadata, exception) -> {
    if (exception != null) {
        log.error("send failed, topic={}, key={}", "orders", order.getOrderId(), exception);
    } else {
        log.debug("sent to partition {} offset {}", metadata.partition(), metadata.offset());
    }
});
producer.flush();   // 关闭前刷新缓冲区,避免缓冲中的消息被丢弃
序列化器与实际消息类型必须匹配:声明为字符串却在发送 JSON 对象,会在发送阶段抛序列化异常,报错信息往往指向客户端日志而不是业务代码,排查时先看生产者日志。
网络持续异常时,无限重试配合过大的总超时会让发送线程长时间阻塞,业务线程跟着被拖住;应把总时限控制在一个业务可接受的范围,并把失败交给应用层处理。

易错点

  • value.serializer 与消息类型不匹配会抛序列化异常,根因要从生产者日志里看,业务代码往往看不出问题
  • 网络抖动时无限重试加过大的总超时,发送线程长时间阻塞并拖累业务线程
  • 关闭幂等却开启重试,重试会写入重复消息,下游必须自行去重
  • 为了降低延迟把批次调到极小,请求数暴增反而压低整体吞吐,且更容易触发限流

数据来源与参考

  • Apache Kafka 官方文档:Producer Design 与 Producer Configs
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌