kafka学习笔记(三、生产者Producer使用及配置参数)

在这里插入图片描述


1.简介

1.1.producer介绍

生产者就是负责向kafka发送消息的应用程序。消息在通过send()方法发往broker的过程中,有可能需要经过拦截器(Interceptor)序列化器(Serializer)分区器(Partitioner)的一系列作用后才能被真正的发往broker
demo:

public class KafkaClient {private static final String brokerList = "localhost:9092";private static final String tipic = "topic-test";public static Properties initConfig() {Properties props = new Properties();props.put("bootstrap.servers", brokerList);props.put("key.serializer", "org.apache.kafka.common.seralization.StringSerializer");props.put("value.serializer", "org.apache.kafka.common.seralization.StringSerializer");props.put("clinet.id", "producer.client.id.test");return props;} public static void main(String[] args) {Properties props = initConfig();KafkaProducer<String, String> producer = new KafkaProducer<>(props);ProducerRecord<String, String> record = new ProducerRecord<>(topic, "kafka producer test.");try {producer.send(record);} catch (Exception e) {e.printStackTrace();}}
}

ProducerRecord类:

public class ProducerRecord<K, V> {private final String topic; // 主题private final Integer partition; // 分区号private final Headers headers; // 消息头部private final K key; // 键private final V value; // 值private final Long timestamp; // 消息的时间戳
}
  • ProducerRecord类中的key属性:
    key用来指定消息的键,不仅是附加消息还可以用来计算分区号而可以让消息发往特定的分区。

    • 同一个key的消息会被划分到同一分区
    • 有key的消息还可以支持日志压缩的功能
  • 必要参数:

    • bootstrap.servers:客户端连接kafka集群所属broker地址(host1:port1),并非需要所有的broker地址,生产者会从给定的broker中查到其他broker信息,建议至少设置两个以上。
    • key.serializer和value.serializer:broker端接收的消息必须以字节数组(byte[])的形式存在。发往broker之前需要将消息中对应的key和value做相应的序列化操作来转换整字节数组。
  • KafkaProducer是线程安全的,可以在多个线程中共享单个KafkaProducer实例,也可以将KafkaProducer实例进行池化来供其他线程使用。
  • 消息发送有三种模式
    • 发后即忘(fire-and-forget):producer.send(record);
    • 同步(sync):producer.send(record).get();
    • 异步(async):producer.send(record, callback); // 回调函数的调用可以保证分区有序。

1.2.生产者拦截器

用来在消息发送前做一些准备工作,比如按照某个规则过滤、修改消息内容等,也可以用来在发送回调逻辑中做一些定制化的需求。

实现: 需自定义实现org.apache.kafka.clinets.producer.ProducerInterception接口。接口中有三个方法:

public ProducerRecord<K, V> onSend(ProducerRecord<K, V> record); // 对消息进行相应的定制化处理// 在消息被应答或发送失败时调用,优先于Callback之前执行。此方法运行在Producer的IO线程中,所以
// 此方法中实现的代码逻辑越简单越好,否则会影响消息的发送速度。
public void onAcknowledgement(RecordMetadata metadata, Exception exception);public void close();

KafkaProducer可以指定多个拦截器形成拦截链。拦截链会按照interceptor.classes参数配置的拦截器顺序来执行。

1.3.序列化

生产者需要用序列化器(Serializer)把对象转换成字节数组才能通过网络发送给kafka。而在对侧,消费者需要反序列化器(Deserializer)把从kafka中收到的字节数组转换成对应的对象。

客户端自带的序列化器都实现了org.apache.kafka.common.serialization.Serializer接口,此接口有三个方法:

public void configure(Map<String, ?> configs, boolean isKey); // 配置当前类,主要确定编码类型
public byte[] serialize(String topic, T data); // 将类型T的数据转换为byte[]
public void close(); // 关闭当前的序列化器,一般情况下为空方法

生产者使用的序列化器和消费者使用的反序列化器是需要一一对应的。

1.4.分区器

为消息分配分区。如果消息ProducerRecord中没有指定partition字段,那么就需要依赖分区器,根据key这个字段来计算partition的值。

kafka提供的默认分区器是org.apache.kafka.clients.producer.internals.DefaultPartitioner,它实现了org.apache.kafka.clients.producer.Partitioner接口,此接口中定义了两个方法:

// 用来计算分区号
public int partition(String topic, Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster);
public void close(); // 关闭分区器的时候用来回收一些资源

Partitioner接口还有一个父接口org.apache.kafka.common.Configurable,此接口只有一个方法:

void configure(Map<String, ?> configs); // 获取配置信息机初始化数据

kafka中除了使用默认的分区器进行分区外还可以使用自定义的分区器,只要实现Partitioner即可。

2.整体架构

在这里插入图片描述

2.1.RecordAccumulator讲解

主要用来缓存消息以便Sender线程可以批量发送,进而减少网络传输的资源以便提升性能。(缓存大小通过生产者客户端参数buffer.memory配置,默认32MB)。

如果生产者发送消息的速度超过发送到服务器的速度,则会导致生产者空间不足,此时KafkaProducer的send()方法调用要么被堵塞要么抛出异常,这个取决于参数max.block.ms的配置,默认为60秒。

  • 主线程发送过来的消息都会被追加到RecordAccumulator的某个双端队列(Deque)中,RecordAccumulator内部为每个分区都维护了一个双端队列,队列的内容就是ProducerBatch,即Deque<ProducerBatch>

    注意: ProducerBatch中包含一个或多个ProducerRecord。ProducerRecord是生产者创建的消息,ProducerBatch是一个消息批次,ProducerRecord会被包含在ProducerBatch中,使字节的使用更加紧凑,也可以减少网络请求的次数以提高整体的吞吐量。

  • 消息写入缓存时,追加到Deque的尾部;Sender读取消息时,从Deque的头部读取。
  • Kafka生产者客户端通过java.io.ByteBuffer实现消息内存的创建和释放,不过频繁的创建和释放是比较耗费资源的,所以在RecordAccumulator内部存在一个BufferPool来实现ByteBuffer的复用,达到缓存高效利用的目的。

    BufferPool只针对特定大小(通过batch.size参数指定,默认16KB)的ByteBuffer进行管理,其他大小的ByteBuffer不会缓存到BufferPool中,我们可以适当的调大batch.size参数以便多缓存一些消息。

2.2.消息进入RecordAccumulator的逻辑

当一条ProducerRecord进入RecordAccumulator时:

  1. 先寻找与消息分区对应的Deque(没有则创建);
  2. 再从这个Deque尾部获取一个ProducerBatch(没有则创建);
  3. 查看ProducerBatch中是否可以写入这个ProducerRecord,可以则写入不可以则需新建ProducerBatch再写入;

    新建ProducerBatch时需评估这条消息是否超过batch.size参数的大小,如不超过则以batch.size参数大小来创建ProducerBatch(使用完这段内存区域后可以通过BufferPool的管理来复用),若超过则以评估的大小来创建(此段内存区域不会被复用)。

2.3.Sender步骤

Sender线程从RecordAccumulator中获取缓存的消息后:

  1. <分区, Deque<ProducerBatch>>转换为<Node, List<ProducerBatch>>,其中Node表示kafka集群的节点;

    对网络连接来说,生产者客户端是与具体的broker节点建立连接,不关心消息的分区;而KafkaProducer的应用逻辑则只关注往哪个分区发送那些消息,所以这里需要做一个应用逻辑层面到网络IO层面的转换

  2. 将转换的<Node, List<ProducerBatch>>进一步封装成<Node, Request>的形式,这样就可以将Request发往各个Node了。

    这里的Request指kafka的各种协议请求,对于消息的发送而言就是指具体的ProducerRequest。

  3. 请求在从Sender线程发往kafka之前还会以Map<NodeId, Deque<Request>>形式保存到InFlightRequest中,以缓存已经发出去但还没有收到相应的请求。

    通过配置参数可以限制每个连接(客户端与Node之间的连接)最多缓存的请求数。此配置参数为:max.in.flight.requests.per.connection,默认为5,即每个连接最多只能缓存5个未响应的请求,超过此值之后就不能再向这个连接发送更多的请求了,除非有缓存的请求收到了响应。

2.4.元数据

值kafka集群的元数据,这些数据包括集群中有主题信息、主题上的分区信息、分区的leader副本信息、follower副本信息、副本的AR和ISR集合信息、集群的节点信息以及控制器节点信息等。

更新元数据信息的条件:

  • 当客户端中没有需要使用的元数据信息,比如没有指定的Topic信息;
  • 超过metadata.max.age.ms时间没有更新元数据信息,此配置默认为5分钟;

更新元数据信息的步骤:

  1. 元数据更新操作时在是在客户端内部进行的,对外部不可见。
  2. 当需要更新元数据信息时,会先挑选出leastLoadedNode,然后向这个Node发送MetadataRequest请求来获取具体的元数据信息。
  3. 这个跟新操作由Sender线程发起,在创建完MetadataRequest之后同样会存入InFlightRequests,之后的步骤和发送消息类似。

元数据信息Sender线程负责更新,主线程需要读取,所以这里的数据同步通过synchronizedfinal关键字来保障。

Producer配置参数

参数默认值含义
bootstarp.servers“”指定连接kafka集群的broker地址(可以只有部分broker地址)
key.serializer“”消息中key对应的序列化类,需实现org.apahce.kafka.common.serialization.Serialiaer
value.serializer“”消息中value对应的序列化类,需实现org.apahce.kafka.common.serialization.Serialiaer
client.id“”指定kafkaProducer对应的客户端id(用来标记消息是从哪个客户端发来的)
acks“1”指定分区中必须有多少个副本收到此条消息生产者才会认为这条消息是成功写入的。它涉及消息的可靠性和吞吐量之间的权衡。asks=1:leader成功写入则返回成功;acks=0:发送消息后不需要等待服务器的响应;scks=-1/all:ISK集合中所有副本成功写入才能收到服务器的成功响应。
buffer.memory32MB生产者客户端中用于缓存消息的缓冲区大小。详见本章节#2.1
batch.size16KB用于指定producerBatch可以复用的内存区域的大小。
max.request.size1MB限制生产者客户端能发送消息的最大值,一般不建议盲目的增大,因为此参数与broker端的message.max.bytes参数有联动。
retries0生产者重试次数
retry.backoff.ms100设定两次重试之间的时间间隔
metadata.max.age30000ms如果在这个时间内无数据没有更新的话会被强制更新
compression.type“none”指定消息的压缩方式,默认情况下消息不会被压缩,,该参数还可以配置为"gzip"、"snappy"和"l24"。消息压缩可极大的减少网络传输量,减低网络的IO,提高整体的性能,是一种以时间换空间的优化方式。
connections.max.idle.ms540000ms指定多久之后关闭闲置的连接
linger.ms0指定生产者发送producerBatch之前等待更过的producerRecord加入ProducerBatch的时间。生产者客户端会在producerBatch被填满或等待时间超过linger.ms值时发送出去。
receive.buffer.bytes32KB设置socket接收消息缓冲区(SO_RECBUF)的大小。如果设置为-1,则使用操作系统的默认值;如果Producer与kafka处于不同的机房,则可以适当调大这个参数值。
send.buffer.bytes128KB设置socket发送消息缓冲区的大小…
request.timeout.ms30000ms配置Producer等待请求响应的最大时间。注意此参数需要比broker端参数replica.lag.time.max.ms的值大,这样可以减少因客户端重试而引起的消息重复的概率
max.block.ms60000用来控制kafkaProducersend()方法和partitionsFor()方法的阻塞时间。当生产者的送缓冲区已满或者没有可用的元数据时,这些方法就会阻塞。
partitioner.class~Defaultpartitioner用来指定分区器,需要实现org.apache.kafka.clients.producer.partitioner
enable.idempotencefalse是否开启幂等性功能。所谓幂等简单说就是对接口的多次调用所产生的结果和调用一次是一致的。生产者在进行重试的时候有可能会重复的写入消息,而使用kafka的幂等性功能之后就可以避免这种情况。
interceptor.classes“”用来设定生产者拦截器,需实现org.apache.kafka.clients.producer.ProducerInterceptor接口。
max.in.fligh.request5限制客户端与Node之间的连接最多缓存的请求数。
per.connection.transactional.idnull设置事务id,必须唯一

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/321033.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis-三主三从高可用集群搭建

正式搭建之前&#xff0c;注意事项&#xff08;坑&#xff09;提前放到最开始&#xff0c;也可以出问题回来看&#xff0c; &#xff08;1&#xff09;第二步中最好将配置文件中的logfile自定义一个目录&#xff0c;以便于在第五步中启动出错的时候迅速定位错误。 &#xff0…

深度学习之基于Vgg16卷积神经网络书法字体风格识别

欢迎大家点赞、收藏、关注、评论啦 &#xff0c;由于篇幅有限&#xff0c;只展示了部分核心代码。 文章目录 一项目简介 二、功能三、系统四. 总结 一项目简介 一、项目背景 书法是中国传统文化的重要组成部分&#xff0c;具有深厚的历史底蕴和独特的艺术魅力。在数字化时代&…

Springboot+Vue项目-基于Java+MySQL的入校申报审批系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

彻底解决python的pip install xxx报错(文末附所有依赖文件)

今天安装pip install django又报错了&#xff1a; C:\Users\Administrator>pip install django WARNING: Ignoring invalid distribution -ip (d:\soft\python\python38\lib\site-pac kages) Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple Collecting djan…

LeetCode 面试经典150题 228.汇总区间

题目&#xff1a; 给定一个 无重复元素 的 有序 整数数组 nums 。 返回 恰好覆盖数组中所有数字 的 最小有序 区间范围列表 。也就是说&#xff0c;nums 的每个元素都恰好被某个区间范围所覆盖&#xff0c;并且不存在属于某个范围但不属于 nums 的数字 x 。 列表中的每个区…

LeetCode:滑动窗口最大值

文章收录于LeetCode专栏 LeetCode地址 滑动窗口最大值 题目 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。   返回 滑动窗口中的最大值 。   示例 1…

详解xml-java语言

1.XML在线学习手册 XML 教程 2.XML可以做什么 1.给两个程序之间进行数据通信。现在用的最多的是JSON。 2.给服务器做配置文件。 3.存储复杂的数据关系。 4.还可以充当小型的数据库。 3.书写格式 <?xml version"1.0" encoding"UTF-8" ?> <…

大数据与会计专业主要学什么课程

大数据与会计专业是一个结合了传统会计知识与现代大数据技术的交叉学科&#xff0c;旨在培养既懂会计又熟悉大数据分析的复合型人才。该专业的学生将会学习以下主要课程内容&#xff1a; 会计基础课程&#xff1a;包括基础会计、财务会计、成本会计、管理会计等&#xff0c;这些…

【UE5】数字人基础

这里主要记录一下自己在实现数字人得过程中涉及导XSens惯性动捕&#xff0c;视频动捕&#xff0c;LiveLinkFace表捕&#xff0c;GRoom物理头发等。 一、导入骨骼网格体 骨骼网格体即模型要在模型雕刻阶段就要雕刻好表捕所需的表情体(blendshape)&#xff0c;后面表捕的效果直…

Elasticsearch 索引 blocks:深入探讨数据保护

Elasticsearch 作为搜索和分析数据的首选分布式引擎在技术领域脱颖而出&#xff0c;尤其是在处理日志、事件和综合文本搜索时。 它的与众不同之处在于它如何让你使用各种块选项调整对其索引的访问。 这对于那些负责技术项目的人&#xff08;比如管理员和编码员&#xff09;来说…

LTE的EARFCN和band之间的对应关系

一、通过EARFCN查询对应band 工作中经常遇到只知道EARFCN而需要计算band的情况&#xff0c;因此查了相关协议&#xff0c;找到了他们之间的对应关系&#xff0c;可以直接查表&#xff0c;非常方便。 具体见&#xff1a; 3GPP TS 36.101 5.7.3 Carrier frequency and EAR…

Leetcode—1235. 规划兼职工作【困难】(upper_bound、自定义排序规则)

2024每日刷题&#xff08;125&#xff09; Leetcode—1235. 规划兼职工作 算法思想 实现代码 class Solution { public:int jobScheduling(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {int n startTime.size();vec…

doris经典bug

在部署完登录web页面查看的时候会发现只有一个节点可以读取信息剩余的节点什么也没读取到 在发现问题后&#xff0c;我们去对应的节点去看log日志&#xff0c;发现它自己绑定到前端的地址上了 现在我们已经发现问题了&#xff0c;以下就开始解决问题 重置doris 首先对be进行操…

代码审计提升系统安全,为企业数字化繁荣保驾护航

近年来&#xff0c;软件安全事件频发&#xff0c;凸显出严峻的信息系统安全形势&#xff0c;传统的安全防护机制已经无法帮助企业实现安全保障。忽视软件代码自身的安全性&#xff0c;仅依靠外围防护、事后修补&#xff0c;无法深层次发现和解决软件迭代开发过程中存在的潜在安…

一键实现在VS Code中绘制流程图

VS Code是一款常用的IDE&#xff0c;受到许多用户的欢迎和喜爱。而其较为出众的一点&#xff0c;就是较好的可拓展性&#xff0c;即丰富的插件应用&#xff0c;这些应用可以极大地提高生产效率&#xff0c;并优化日常使用。 流程图是一种直观的图示方法&#xff0c;可以用简明…

Fastadmin 日常项目常见用法整理

ps&#xff1a;自己使用笔记备用&#xff0c;不间断更新&#xff0c;常见功能点 一&#xff0c;数据库后缀 结尾字符示例类型要求字段说明timerefreshtimebigint/datetime识别为日期时间型数据&#xff0c;自动创建选择时间的组件imagesmallimagevarchar识别为图片文件&#…

谷歌推广和seo收录是一回事吗?

那自然不是一回事&#xff0c;谷歌推广一般指的是谷歌的广告服务&#xff0c;通过购买广告位&#xff0c;以便用户在谷歌搜索特定关键词时显示您的广告&#xff0c;这种方式通常基于点击收费&#xff0c;意味着您只有在有人点击您的广告时才需要支付费用。谷歌推广可以让您的网…

加密技术在保护企业数据中的应用

加密技术是企业数据保护的核心&#xff0c;对于维护信息安全至关重要。透明加密技术使文件加密后不改变用户对文件的使用习惯&#xff0c;内部文件打开自动解密&#xff0c;存储自动加密&#xff0c;一旦离开使用环境&#xff0c;加密文件将无法正常读取&#xff0c;从而保护文…

【Java】第二讲:字符串相关类

个人主页&#xff1a;深情秋刀鱼-CSDN博客 Java专栏&#xff1a;Java程序设计 目录 一、String 1.Java中的数据类型 2.字符串概述 3.字符串构造方法 4.字符串构造内存原理 5.字符串比较 6.字符串常见方法 二、StringBuilder 1.定义 2.常用方法 3.StringBuilder内存分…

04-xss获取cookie实验

二、开发XSS服务器端 1、确认实验环境 攻击者服务器&#xff1a;192.168.74.134&#xff0c;将获取到cookie数据保存到该服务器的数据库中&#xff0c;运行PHP代码暴露一个接收Cookie的URL地址。 正常Web服务器&#xff1a;192.168.74.133&#xff0c;用于正常的用户访问的目…