从源码分析如何优雅的使用 Kafka 生产者

聊聊 Kafka:Producer 源码解析 一、前言 前面几篇我们讲了关于 Kafka 的基础架构以及搭建,从这篇开始我们就来源码分析一波。我们这用的 Kafka 版本是 2.7.0,其 Client 端是由 Java 实现,Server 端是由 Scala 来实现的,在使用 Kafka 时,Client 是用户最先接触到的部分,因此,我们从 Client 端开始,会先从 Producer 端开始,今天我们就来对 Producer 源码解析一番。 二、Producer 使用 首先我们先通过一段代码来展示 KafkaProducer 的使用方法。 阅读详情

前言

其中有朋友咨询在大量消息的情况下 Kakfa 是如何保证消息的高效及一致性呢?

正好以这个问题结合 Kakfa 的源码讨论下如何正确、高效的发送消息。

内容较多,对源码感兴趣的朋友请系好安全带(源码基于 v0.10.0.0 版本分析)。同时最好是有一定的 Kafka 使用经验,知晓基本的用法。

简单的消息发送

在分析之前先看一个简单的消息发送是怎么样的。

以下代码基于 SpringBoot 构建。

首先创建一个
org.apache.kafka.clients.producer.Producer 的 bean。

主要关注 bootstrap.servers,它是必填参数。指的是 Kafka 集群中的 broker 地址,例如 127.0.0.1:9094。

其余几个参数暂时不做讨论,后文会有详细介绍。

接着注入这个 bean 即可调用它的发送函数发送消息。

这里我给某一个 Topic 发送了 10W 条数据,运行程序消息正常发送。

但这仅仅只是做到了消息发送,对消息是否成功送达完全没管,等于是纯 异步的方式。

同步

那么我想知道消息到底发送成功没有该怎么办呢?

其实 Producer 的 API 已经帮我们考虑到了,发送之后只需要调用它的 get() 方法即可同步获取发送结果。

发送结果:

这样的发送效率其实是比较低下的,因为每次都需要同步等待消息发送的结果。

异步

为此我们应当采取异步的方式发送,其实 send()方法默认则是异步的,只要不手动调用 get() 方法。

但这样就没法获知发送结果。

所以查看 send() 的 API 可以发现还有一个参数。

Future <RecordMetadata> send(ProducerRecord<K, V> producer,Callback callback);

Callback 是一个回调接口,在消息发送完成之后可以回调我们自定义的实现。

执行之后的结果:

同样的也能获取结果,同时发现回调的线程并不是上文同步时的 主线程,这样也能证明是异步回调的。

同时回调的时候会传递两个参数:

  • RecordMetadata 和上文一致的消息发送成功后的元数据。
  • Exception 消息发送过程中的异常信息。

但是这两个参数并不会同时都有数据,只有发送失败才会有异常信息,同时发送元数据为空。

所以正确的写法应当是:

至于为什么会只有参数一个有值,在下文的源码分析中会一一解释。

源码分析

现在只掌握了基本的消息发送,想要深刻的理解发送中的一些参数配置还是得源码说了算。

首先还是来谈谈消息发送时的整个流程是怎么样的, Kafka 并不是简单的把消息通过网络发送到了 broker中,在 Java 内部还是经过了许多优化和设计。

发送流程

为了直观的了解发送的流程,简单的画了几个在发送过程中关键的步骤。

从上至下依次是:

  • 初始化以及真正发送消息的 kafka-producer-network-thread IO 线程。
  • 将消息序列化。
  • 得到需要发送的分区。
  • 写入内部的一个缓存区中。
  • 初始化的 IO 线程不断的消费这个缓存来发送消息。

步骤解析

接下来详解每个步骤。

初始化

调用该构造方法进行初始化时,不止是简单的将基本参数写入 KafkaProducer。比较麻烦的是初始化 Sender 线程进行缓冲区消费。

初始化 IO 线程处:

可以看到 Sender 线程有需要成员变量,比如:

acks,retries,requestTimeout

等,这些参数会在后文分析。

序列化消息

在调用 send() 函数后其实第一步就是序列化,毕竟我们的消息需要通过网络才能发送到 Kafka。

其中的 valueSerializer.serialize(record.topic(),record.value()); 是一个接口,我们需要在初始化时候指定序列化实现类。

我们也可以自己实现序列化,只需要实现
org.apache.kafka.common.serialization.Serializer 接口即可。

路由分区

接下来就是路由分区,通常我们使用的 Topic 为了实现扩展性以及高性能都会创建多个分区。

如果是一个分区好说,所有消息都往里面写入即可。

但多个分区就不可避免需要知道写入哪个分区。

通常有三种方式。

指定分区

可以在构建 ProducerRecord 为每条消息指定分区。

这样在路由时会判断是否有指定,有就直接使用该分区。

这种一般在特殊场景下会使用。

自定义路由策略

如果没有指定分区,则会调用 partitioner.partition 接口执行自定义分区策略。

而我们也只需要自定义一个类实现
org.apache.kafka.clients.producer.Partitioner 接口,同时在创建 KafkaProducer 实例时配置 partitioner.class 参数。

通常需要自定义分区一般是在想尽量的保证消息的顺序性。

或者是写入某些特有的分区,由特别的消费者来进行处理等。

默认策略

最后一种则是默认的路由策略,如果我们啥都没做就会执行该策略。

该策略也会使得消息分配的比较均匀。

来看看它的实现:

简单的来说分为以下几步:

  • 获取 Topic 分区数。
  • 将内部维护的一个线程安全计数器 +1。
  • 与分区数取模得到分区编号。

其实这就是很典型的轮询算法,所以只要分区数不频繁变动这种方式也会比较均匀。

写入内部缓存

在 send() 方法拿到分区后会调用一个 append() 函数:

该函数中会调用一个 getOrCreateDeque() 写入到一个内部缓存中 batches。

消费缓存

在最开始初始化的 IO 线程其实是一个守护线程,它会一直消费这些数据。

通过图中的几个函数会获取到之前写入的数据。这块内容可以不必深究,但其中有个 completeBatch 方法却非常关键。

调用该方法时候肯定已经是消息发送完毕了,所以会调用 batch.done() 来完成之前我们在 send() 方法中定义的回调接口。

从这里也可以看出为什么之前说发送完成后元数据和异常信息只会出现一个。

Producer 参数解析

发送流程讲完了再来看看 Producer 中比较重要的几个参数。

acks

acks 是一个影响消息吞吐量的一个关键参数。

主要有 [all、-1,0,1] 这几个选项,默认为 1。

由于 Kafka 不是采取的主备模式,而是采用类似于 Zookeeper 的主备模式。

前提是 Topic 配置副本数量 replica>1。

当 acks=all/-1 时:

意味着会确保所有的 follower 副本都完成数据的写入才会返回。

这样可以保证消息不会丢失!

但同时性能和吞吐量却是最低的。

当 acks=0 时:

producer 不会等待副本的任何响应,这样最容易丢失消息但同时性能却是最好的!

当 acks=1 时:

这是一种折中的方案,它会等待副本 Leader 响应,但不会等到 follower 的响应。

一旦 Leader 挂掉消息就会丢失。但性能和消息安全性都得到了一定的保证。

batch.size

这个参数看名称就知道是内部缓存区的大小限制,对他适当的调大可以提高吞吐量。

但也不能极端,调太大会浪费内存。小了也发挥不了作用,也是一个典型的时间和空间的权衡。

上图是几个使用的体现。

retries

retries 该参数主要是来做重试使用,当发生一些网络抖动都会造成重试。

这个参数也就是限制重试次数。

但也有一些其他问题。

  • 因为是重发所以消息顺序可能不会一致,这也是上文提到就算是一个分区消息也不会是完全顺序的情况。
  • 还是由于网络问题,本来消息已经成功写入了但是没有成功响应给 producer,进行重试时就可能会出现 消息重复。这种只能是消费者进行幂等处理。

高效的发送方式

如果消息量真的非常大,同时又需要尽快的将消息发送到 Kafka。一个 producer 始终会收到缓存大小等影响。

那是否可以创建多个 producer 来进行发送呢?

  • 配置一个最大 producer 个数。
  • 发送消息时首先获取一个 producer,获取的同时判断是否达到最大上限,没有就新建一个同时保存到内部的 List中,保存时做好同步处理防止并发问题。
  • 获取发送者时可以按照默认的分区策略使用轮询的方式获取(保证使用均匀)。

这样在大量、频繁的消息发送场景中可以提高发送效率减轻单个 producer 的压力。

关闭 Producer

最后则是 Producer 的关闭,Producer 在使用过程中消耗了不少资源(线程、内存、网络等)因此需要显式的关闭从而回收这些资源。

默认的 close() 方法和带有超时时间的方法都是在一定的时间后强制关闭。

但在过期之前都会处理完剩余的任务。

所以使用哪一个得视情况而定。

总结

本文内容较多,从实例和源码的角度分析了 Kafka 生产者。

希望看完的朋友能有收获,同时也欢迎留言讨论。

Kafka 读写示例 Kafka 是一款流行的分布式消息队列系统,具有高吞吐量、可扩展性和持久性等优点。本文将介绍如何使用 Kafka 进行消息的生产和消费。Kafka 是一款强大的分布式消息队列系统,具有高吞吐量、可扩展性和持久性等优点。通过配置 Kafka 的生产者和消费者,可以实现高效的消息生产、消费和处理。在实际应用中,可以通过优化 Kafka 的配置和使用消费者组等方式,提高 Kafka 的性能和可靠性。 阅读详情

相关推荐

内存优化--LOGBACK导致内存告警

一.故事背景 由于开辟新市场需要,开发了新的项部署在海外平台,其中最消耗内存的功能是消费kafka消息(最开始预计一天有1千万的量),部署完之后运行一段时间发现出现内存告警问题。 二.分析问题 出现内存告警,(新项目是低配置机器 2C4G * 2台)第一个念头是去查看堆空间设置的情况,看到jvm启动命令中堆空间都是直接指定大小,说明问题不是出在堆空间 -Xmx3g -Xms3g 先不管这些,去查看总的内存使用情况,发现总的内存空间使用将近有92% = 3.68G,那么这多出来使用的0.6

qq_33199919的博客 6053

KafkaProducer-kafka生产者Java客户端

KafkaProducer(org.apache.kafka.clients.producer.KafkaProducer)是一个用于向kafka集群发送数据的Java客户端。该Java客户端是线程安全的,多个线程可以共享同一个producer实例,而且这通常比在多个线程中每个线程创建一个实例速度要快些。

cjf_wei的博客 3万+

SPSS线性混合模型实战:手把手复现一篇老年认知研究的统计结果(含代码)

本文详细介绍了如何使用SPSS线性混合效应模型复现老年认知研究的统计结果,涵盖数据准备、模型构建、结果解读及可视化全流程。特别针对重复测量数据分析,提供了SPSS菜单操作与语法编写的实用技巧,帮助研究者高效处理复杂数据并验证模型假设。

weixin_42562079的博客 518

KafkaProducer使用介绍、参数配置以及核心源码解析

前言 Kafka,作为目前在大数据领域应用最为广泛的消息队列,其内部实现和设计有很多值得深入研究和分析的地方,使用kafka首先需要接触到producer的开发,然后是consumer开发,自0.8.2.x版本以后,kafka提供了java 版本的producer以代替以前scala版本的producer,下面进行producer的解析。 Producer 概要设计 发送简略流程图 K...

qq_18581221的博客 1万+

ANSYS Workbench接触分析实战:从算法选择到收敛难题破解

本文深入解析ANSYS Workbench接触分析的核心技术与实战技巧,涵盖四大接触算法选择、收敛难题破解秘籍及典型场景参数设置。通过实际案例演示如何优化接触刚度、pinball区域和非对称行为等关键参数,帮助工程师有效解决结构非线性问题,提升仿真效率和精度。

weixin_28705087的博客 361

ThinkPad X230魔改指南:从博通网卡驱动到1080P屏显全攻略(附Sonoma避坑清单)

本文详细介绍了ThinkPad X230的全面改造方案,包括博通网卡驱动(BCM94352HMB)的安装与调试、1080P屏幕改装技术以及macOS Sonoma系统的适配优化。通过硬件升级和软件调优,使这台经典商务本焕发新生,适合DIY爱好者和技术极客参考实践。

weixin_30379531的博客 588

kafka 回调超时_从源码分析如何优雅的使用 Kafka 生产者

前言在大量消息的情况下 Kakfa 是如何保证消息的高效及一致性呢?正好以这个问题结合 Kakfa 的源码讨论下如何正确、高效的发送消息。内容较多,对源码感兴趣的朋友请系好安全带 (源码基于 v0.10.0.0 版本分析)。同时最好是有一定的 Kafka 使用经验,知晓基本的用法。简单的消息发送在分析之前先看一个简单的消息发送是怎么样的。(以下代码基于 SpringBoot 构建。)首先创建一个 ...

weixin_42135773的博客 500

代谢组数据分析(三):代谢组降维分析

本文详细介绍了代谢组学中常用的降维分析方法,包括PCA、PLS-DA和OPLS-DA。PCA通过线性变换降低数据维度,便于数据可视化和异常值检测;PLS-DA是一种有监督的模式识别方法,适用于分类和预测;OPLS-DA通过正交分解避免过拟合,更准确地筛选差异代谢物。降维分析在揭示样本间差异和发现生物标志物方面具有重要意义

专注生信领域 3792

kafka 回调超时_源码分析:如何才能优雅的使用 Kafka 生产者

前言之前有朋友提起过在大量消息的情况下 Kakfa 是如何保证消息的高效及一致性呢?正好以这个问题结合 Kakfa 的源码讨论下如何正确、高效的发送消息。内容较多,对源码感兴趣的朋友请系好安全带 (源码基于 v0.10.0.0 版本分析)。同时最好是有一定的 Kafka 使用经验,知晓基本的用法。简单的消息发送在分析之前先看一个简单的消息发送是怎么样的。以下代码基于 SpringBoot 构建。首...

weixin_33592736的博客 347

【OpenClaw从入门到精通】第34篇:医疗AI的“Agent OS”时代:基于WiseClaw构建医院专属智能体平台(2026实测版)

2026年医疗AI迈入实战落地新阶段,全球首个医疗OpenClaw平台WiseClaw正式发布,香港中文大学(深圳)医院完成业内首个私有化部署。本文基于真实医疗场景需求与公开技术资料,系统拆解医疗智能体平台的建设逻辑:从医疗Agent OS的五大核心特性切入,详解门诊病历质控、用药审查、医院运行管理三大临床场景的智能体搭建流程,提供完整的私有化部署代码、安全配置方案与实操演示。文章兼顾新手入门与进阶需求,严格遵循医疗合规要求,强调“只读不写+人工复核”原则,所有方案均经过虚拟实测验证。

专注于人工智能、软件开发、工控自动化、工厂数字化及智能化等领域,希望和大家共同进步! 788

【YOLO11改进 - 特征融合】利用Hyper-YOLO 的混合聚合网络(MANet)改进yolo11,提升基础网络的特征提取能力

【YOLO11改进 - 特征融合】利用Hyper-YOLO 的混合聚合网络(MANet)改进yolo11,提升基础网络的特征提取能力

专注于图像领域,主要研究内容包括计算机视觉和深度学习,特别是在图像分类、目标检测和图像生成等方面有深入的研究和实践经验。 905

kafka源码_源码分析:如何才能优雅的使用 Kafka 生产者

前言之前有朋友提起过在大量消息的情况下 Kakfa 是如何保证消息的高效及一致性呢?正好以这个问题结合 Kakfa 的源码讨论下如何正确、高效的发送消息。内容较多,对源码感兴趣的朋友请系好安全带 (源码基于 v0.10.0.0 版本分析)。同时最好是有一定的 Kafka 使用经验,知晓基本的用法。简单的消息发送在分析之前先看一个简单的消息发送是怎么样的。以下代码基于 SpringBoot 构建。首...

weixin_39928099的博客 62

第4-4课:状态压缩与动态规划

什么是状态压缩 动态规划问题中重要的一环就是确定状态的定义,在大多数情况下,状态中所包含的信息并不多,比如线性规划问题的状态一般表示为 d[i,j](i 表示状态的位置,j 表示状态的阶段),算法实现时可用二维数组保存计算过程中的状态。但是也有一些问题,它的状态中包含的信息很多,比如它的状态可能是一个集合中各个元素的情况,或者是像铺瓷砖问题这样,是某一行的覆盖状态。如果沿用简单的状态表示方法,则可...

oRbIt 的专栏 701

kafka源码_从源码分析如何优雅的使用 Kafka 生产者

前言在大量消息的情况下 Kakfa 是如何保证消息的高效及一致性呢?正好以这个问题结合 Kakfa 的源码讨论下如何正确、高效的发送消息。内容较多,对源码感兴趣的朋友请系好安全带 (源码基于 v0.10.0.0 版本分析)。同时最好是有一定的 Kafka 使用经验,知晓基本的用法。简单的消息发送在分析之前先看一个简单的消息发送是怎么样的。(以下代码基于 SpringBoot 构建。)首先创建一个 ...

weixin_39524834的博客 63

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

从源码分析如何优雅地使用 Kafka 生产者

简单的消息发送 在分析之前先看一个简单的消息发送是怎么样的。 以下代码基于 SpringBoot 构建。 首先创建一个org.apache.kafka.clients.producer.Producer的 bean。 主要关注bootstrap.servers,它是必填参数。指的是 Kafka 集群中的 broker 地址,例如127.0.0....

weixin_34202952的博客 111

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: “DBA攻坚指南”,Oracle与MySQL实战手册,受益匪浅,良心推荐
下一篇: Kafka 的这些原理你懂吗
JavaMonsterr
博客等级 码龄4年 211粉丝 481原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值