kafka 生产者是如何发送消息的?

Kafka 生产者发送消息的过程是一个异步流程,旨在实现高吞吐量和可靠性。这个过程主要涉及两个核心线程:主线程Sender 线程

下面是消息从创建到被 Broker 确认接收的详细步骤:

生产者发送消息的核心流程

  1. 创建消息 (主线程)

    用户首先需要创建一个 ProducerRecord 对象,它包含了消息需要发送到的 Topic分区 (Partition) (可选)、键 (Key) (可选)和 值 (Value)

  2. 拦截器与序列化 (主线程)

    • 拦截器 (Interceptors): 在消息被序列化之前,它可以被一个或多个拦截器处理。用户可以自定义拦截器来修改消息内容或进行一些统计工作。
    • 序列化器 (Serializer): 由于消息是通过网络发送的,生产者需要将消息的 Key 和 Value 对象序列化成字节数组 (byte arrays)。 Kafka 客户端配置中必须指定 Key 和 Value 的序列化器。
  3. 分区器选择分区 (主线程)

    接下来,消息会经过分区器 (Partitioner) 来确定它将被发送到 Topic 的哪一个分区。 分区策略如下:

    • 指定分区: 如果在 ProducerRecord 中明确指定了分区号,那么分区器将直接使用该分区。
    • 使用消息的 Key: 如果没有指定分区但指定了 Key,Kafka 默认会使用 murmur2 哈希算法对 Key 进行哈希,然后根据哈希值对分区总数取模,从而为该 Key 选择一个固定的分区。 这保证了拥有相同 Key 的消息总能被发送到同一个分区,从而保证了消息在分区内的顺序性。
    • 未指定分区和 Key (粘性分区策略): 如果既没有指定分区也没有指定 Key,从 Kafka 2.4 版本开始,默认采用粘性分区策略 (Sticky Partitioner)。 生产者会随机选择一个分区并尽可能地向这个分区发送消息,直到该分区的批次(batch)满了或者等待时间到了,才会再随机选择下一个"粘性"分区。 这种策略减少了网络请求,降低了延迟并提升了吞吐量。在旧版本中,这里使用的是轮询策略 (Round-robin)。
  4. 消息累加器 (RecordAccumulator)

    确定分区后,消息并不会立即被发送出去,而是被放入一个消息累加器 (RecordAccumulator) 中。 这个累加器在生产者客户端内部为每个分区维护了一个双端队列 (Deque),消息会被追加到对应分区队列的批次 (ProducerBatch) 中。 这样做是为了将多个消息打包成一个批次进行发送,从而大大减少网络请求次数,提高吞吐量。

  5. Sender 线程发送消息

    Sender 是一个独立的 I/O 线程,它的主要工作是从消息累加器中获取准备好的消息批次,并将它们发送到对应的 Kafka Broker。 Sender 线程的发送时机由两个关键参数控制:

    • batch.size: 当累加到某个分区的消息大小总和达到这个值(默认为 16KB)时,Sender 线程就会发送这个批次。
    • linger.ms: 如果消息迟迟没有达到 batch.size,Sender 线程不会一直等待。当超过了 linger.ms 指定的时间(默认为 0ms)后,即使批次没满,也会被发送出去。

    因此,减小 batch.sizelinger.ms 有利于降低延迟,而增大它们则有利于提升吞吐量。

  6. Broker 的响应与 Ack 确认机制

    当 Broker 收到消息后,会向生产者返回一个响应。这个响应的类型由生产者的 acks (acknowledgements) 参数决定,这是保证消息可靠性的核心机制:

    • acks=0: 生产者发送消息后不等待任何来自 Broker 的确认。 这种模式下延迟最低,吞吐量最高,但数据丢失的风险也最大(即"发后即忘")。
    • acks=1 (默认值): 生产者只需等待分区的 Leader 副本成功写入消息并返回确认即可。 这种模式在性能和可靠性之间取得了较好的平衡。但如果 Leader 副本写入成功后但在 Follower 副本同步完成前宕机,消息仍有丢失的风险。
    • acks=all (或 -1): 生产者需要等待 Leader 和所有 ISR (In-Sync Replicas, 同步副本列表) 中的 Follower 副本都成功写入消息后,才会收到确认。 这是最可靠的级别,可以最大限度地保证消息不丢失,但延迟也最高。
  7. 重试机制

    如果消息发送失败(例如网络抖动或 Broker 发生故障),生产者会根据配置的 retries 次数自动进行重试。 但需要注意的是,如果 max.in.flight.requests.per.connection 参数大于1,重试可能会导致消息乱序。

相关推荐
何中应7 小时前
RabbitMQ集群搭建
分布式·rabbitmq
薪火铺子7 小时前
Redis 分布式锁与 Redisson 原理深度解析
java·redis·分布式·后端
skilllite作者8 小时前
Deer-Flow 工作流引擎深度评测报告
java·大数据·开发语言·chrome·分布式·架构·rust
摇滚侠8 小时前
Java 项目教程《黑马商城》微服务拆分 20 - 22
java·分布式·架构
乐之者v9 小时前
Kafka 跨服数据同步
分布式·kafka
喜欢流萤吖~10 小时前
分布式搜索引擎:Elasticsearch 从入门到实战
分布式·elasticsearch·搜索引擎
PawSQL10 小时前
同一条SQL,单机秒回,分布式集群卡成PPT——问题究竟出在哪?
数据库·分布式·sql
富士康质检员张全蛋10 小时前
Kafka 消息查找流程和消息读取流程
分布式·kafka
深蓝轨迹12 小时前
Kafka入门教程--帮你理清所有概念和细节
分布式·zookeeper·kafka
小尘要自信12 小时前
Kafka 从原理到实践:分区副本机制、生产消费可靠性、以及如何避开那些年踩过的坑
分布式·kafka