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.mfbz.cn/a/599289.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Ecovadis认证是什么?

Ecovadis认证是一种企业社会责任&#xff08;CSR&#xff09;评估和评级的认证&#xff0c;旨在衡量企业在环境、劳工和人权、道德以及可持续采购四个方面的可持续发展表现。该认证已成为全球范围内许多公司和组织的评估标准之一&#xff0c;有助于提高企业的会声誉和可持续发展…

LeetCode:滑动窗口最大值

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

浅谈操作系统中的重要概念——线程(3)——设计模式

文章目录 一、什么是设计模式&#xff1f;二、单例模式2.1、饿汉模式2.2、懒汉模式2.3、多线程情况下调用 饿汉模式与懒汉模式 谁是安全的&#xff1f;&#xff1f;&#xff08;重点&#xff09; 三、工厂模式 一、什么是设计模式&#xff1f; 设计模式就相当于菜谱&#xff0…

呆滞物料规范管理了,问题就好办了

对于制造企业来说&#xff0c;库存是生存和发展的重要保障&#xff0c;过高的库存会占用企业大量的资金和管理成本&#xff0c;影响企业的正常生产&#xff0c;然而多数中小制造企业还在用人工干预管理&#xff0c;如何控制呆滞物料成为仓储管理的一大难题。 什么是呆滞料 呆滞…

基于Spring Boot的家具网站设计与实现

基于Spring Boot的家具网站设计与实现 开发语言&#xff1a;Java 框架&#xff1a;springboot JDK版本&#xff1a;JDK1.8 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea 系统部分展示 系统前台主界面图&#xff0c;用户可进入家具网站可查看…

裸辞、裁员、老板跑路、被迫失业,未来是「超级个体」的时代

本期我们邀请的程序员是张立强&#xff0c;裸辞、裁员、老板跑路、被迫失业&#xff0c;管理层利益争夺&#xff0c;职业转型&#xff0c;工作五年&#xff0c;攒出了十年经验。程序员如何寻找自己的第二曲线&#xff0c;不妨听听立强的看法。 裸辞失业 大家好&#xff0c;我…

纯血鸿蒙APP实战开发——手写绘制及保存图片

介绍 本示例使用drawing库的Pen和Path结合NodeContainer组件实现手写绘制功能。手写板上完成绘制后&#xff0c;通过调用image库的packToFile和packing接口将手写板的绘制内容保存为图片&#xff0c;并将图片文件保存在应用沙箱路径中。 效果图预览 使用说明 在虚线区域手写…

使用Matplotlib库绘制了一个图形

前言 本文学习的用Matplotlib绘制一个正弦函数曲线&#xff0c;大家跟我来 第一步&#xff1a;编辑代码 import numpy as np import matplotlib.pyplot as plt xnp.linspace(0,10,1000) #用NumPy中的linspace函数生成一个包含1000个在0到10之间均匀分布的数值的数组&#xf…

瑞友天翼应用虚拟化系统SQL注入致远程代码执行漏洞复现

0x01 产品简介 瑞友天翼应用虚拟化系统是西安瑞友信息技术资讯有限公司研发的具有自主知识产权,基于服务器计算架构的应用虚拟化平台。它将用户各种应用软件集中部署在瑞友天翼服务器(群)上,客户端通过WEB即可快速安全的访问经服务器上授权的应用软件,实现集中应用、远程接…

网络基础(1)详解

目录 1.计算机网络背景 2.网络协议 3.网络中的地址管理 1.计算机网络背景 1.1 网络发展 (1)计算机从独立模式到网络互联(多态计算机连接共享数据)再到局域网LAN(通过交换机和路由器连接)接着是广域网WAN 1.2 协议 协议就是双方的一种约定. 为什么要有协议? 因为在数据长距…

SRC公益漏洞挖掘思路分享

0x00 前言 第一次尝试挖SRC的小伙伴可能会觉得挖掘漏洞非常困难&#xff0c;没有思路&#xff0c;不知道从何下手&#xff0c;在这里我分享一下我的思路 0x01 挖掘思路 确定自己要挖的漏洞&#xff0c;以及该漏洞可能存在的功能点&#xff0c;然后针对性的进行信息收集 inurl…

jenkins 部署springboot 项目

文章目录 持续集成指定tag发布 基于Jenkins拉取GitLab的SpringBoot代码进行构建发布到测试环境实现持续集成 基于Jenkins拉取GitLab指定发行版本的SpringBoot代码进行构建发布到生产环境实现CD实现持续部署 持续集成 为了让程序代码可以自动推送到测试环境基于Docker服务运行…

工控人机交互界面编辑软件附描述(电脑软件分享)

HMI 概述&#xff1a;本文为分享型文档 本文摘要 昆仑通泰触摸屏软件分享。   给触摸屏下载程序时使用。   本人用过案例西门子s7-1200/200smart ST30与触摸屏型号“TPC1061Ti”通讯。 文章目录 本文摘要1.MCGS组态环境嵌入式版&#xff0c;大部分人用过此款&#xff0c;容…

巨控GRM561/562/563/564Q杀菌信息远程监控

摘要 通过程序编写、手机APP画面制作等运行系统&#xff0c;实现电脑及手机APP显示的历史曲线画面和数据图形化的实时性。 不仅流程效率提升90%以上&#xff0c;同时为杀菌生产提供有利的质量保障&#xff0c;还有效规避因触屏及内存卡的突发异常导致历史数据的丢失&#xff0…

网络安全之交换基础

交换属于二层技术。路由器&#xff08;router&#xff09;是三层设备&#xff0c;可以基于IP地址转发&#xff0c;但需要路由表来记录。 交换机&#xff08;switch&#xff09;是二层设备&#xff0c;网桥&#xff08;switch&#xff09;也是二层设备&#xff0c;这两个都是基…

uniapp-ios支付

uniapp安卓包中的微信,支付宝逻辑放在iOS测试包中也能使用. 但询问iOS开发者后得知,有支付相关功能的app要上架苹果,必须先有苹果支付,不然苹果审核不给过.甚至没有支付逻辑,但打包时有支付相关的SDK也不行,苹果会认为你偷偷做了支付逻辑,想要绕开他. 一. 去苹果开发者后台把…

编程题库-Python、Java、C++、C 应有尽有!!!

目录 网址注册账号题库 网址 传送门 http://oj.ecustacm.cn/ 这个↑链接是网站 注册账号 刚进去是这个页面 注册一个账号 题库 点击上方的问题菜单&#xff0c;进入题库 点击题目标题进入题目&#xff0c;我就随便点一道 这里面一般会有样例输入和输出以及题目描述 点…

语音识别--光谱门控降噪

⚠申明&#xff1a; 未经许可&#xff0c;禁止以任何形式转载&#xff0c;若要引用&#xff0c;请标注链接地址。 全文共计7267字&#xff0c;阅读大概需要3分钟 &#x1f308;更多学习内容&#xff0c; 欢迎&#x1f44f;关注&#x1f440;【文末】我的个人微信公众号&#xf…

redis 使用记录

redis 使用记录 下载运行配置文件启动 参考 下载 github: Redis for Windows 或者从百度网盘下载 Redis version 3.2.100 链接: https://pan.baidu.com/s/1kxNOuZFunvVhVy1cfQzCDA?pwdpibh 运行 双击运行 运行效果 如果出错&#xff1a;查看是否项目路径是否包含中文 配…

矩阵快速幂

要想知道矩阵快速幂&#xff0c;我们先了解一下什么叫快速幂和矩阵乘法 一、快速幂 快速幂算法是用来快速计算指数表达式的值的&#xff0c;例如 210000000,普通的计算方法 2*2*2*2…10000000次&#xff0c;如果一个数字的计算都要计算那么多次的话&#xff0c;那么这个程序一…
最新文章