了解Kafka生产者
了解Kafka生产者
之前对kafka的整体架构有浅显的了解,这次正好有时间,准备深入了解一下kafka,首先先从数据的生产者开始吧。
生产者的整体架构
可以看到整个生产者进程主要由两个线程进行协调工作,其中一个是主线程,首先由KafkaProducer创建消息,然后通过拦截器、消息序列化器、分区器的处理后,缓存到消息累加器中。另一个是Sender线程,负责从消息累加器中获取消息,并发送至Kafka集群中。
下面来具体分析各个组件的作用,以便加深了解。
拦截器: 从名字就可看出是按照一定规则对消息进行过滤。这个具体的规则可以自己去重写kafka中的ProducerInterceptorPrefix类中的onSend方法来实现。之后在KafkaProducer的配置参数 interceptor.classes中指定该拦截器来进行使用。还可以指定多个拦截器,组成拦截链。
序列化器:生产者需要使用它将消息对象转化为字节数组发送给kafka集群。消费者端进行反序列化还原消息对象。kafka中自带序列化器StringSerializer可对String、VyteArray、ByteBuffer等等类型进行序列化。kafka支持自定义序列化器,实现Serializer,重写serialize方法,即可实现自定义序列化器。修改配置文件中的value.serializer参数为自定义的类名即可。
分区器:顾名思义,分区器就是控制消息最终发往那个分区。若ProducerRecord中指定了partition字段,将发往指定的分区。反之,将根据消息的key来计算partition的值,拥有相同key的消息会被写入同一分区,key为null的消息,将会以轮询的方式发往topic内的各个可用分区。topic中的分区数量不变时,key与分区之间的映射关系保持不变。当topic内的分区数量变化时,该关系将难以保持。
注意:
如果key为null,计算得到的分区号仅为可用分区中的任意一个。当key不为null时,计算得到的分区号是所有分区中的任意一个。
当然,分区器也可以自定义,实现Partitioner中的partition方法即可。同样也是通过配置参数partitioner.class来显式指定这个分区器。
消息累加器:RecordAccumulator主要用来缓存消息,使Sender线程可以批量发送消息,进而减少网络传输的前期准备和收尾的资源消耗,提升性能和效率。缓存大小可以通过buffer.memory配置,默认值32MB。主程序生产的消息(ProducerRecord)都会追加到ProducerBatch尾部。消息累加器里面维护了一个Deque,他们之间的关系是多个ProducerRecord组成了一个ProducerBatch,多个ProducerBatch组成了一个Deque,这样的结构同样也是为了使消息排列更紧凑,提升效率和性能。
消息在生产端的生命历程
在RecordAccumulator内部还有一个BufferPool,用来实现ByteBuffer的复用,以实现缓存的高效利用,不过BufferPool只针对特定大小的ByteBuffer,其他大小的ByteBuffer不会缓存进BufferPool,这个特定大小由batch.size来指定,默认值为16KB。
当消息进入RecordAccumulator时,会先寻找指定分区所对应的Deque(若无将创建),再从Deque获取尾部的PoducerBatch(若无将创建),查看是否还能写入该消息(ProducerRecord),若可以则写入,否则将创建一个新的ProducerRecord,在创建时评估消息大小是否超过batch.size的大小,若不超过,PoducerBatch大小为该值,超过的话,将以消息大小创建PoducerBatch。换句话说,该PoducerBatch中仅有一条消息。
以batch.size创建的PoducerBatch可以通过BufferPool的管理来进行复用。
Sender从RecordAccumulator中获取缓存的消息之后,会将消息格式<分区,Deque>转换为<Node,List>,Node为kafka集群中的broker节点。之后Sender还会进一步封装成<Node,Request>的形式,这样就可以将Request请求发往各个Node了。请求在从Sender线程发往Kafka之前还会保存到InFlightRequests中,消息格式为Map<NodeId,Deque>,主要作用是缓存了已经发出去但还没有收到响应的请求。InFlightRequests可以通过配置参数来限制每个连接最多缓存的请求数。配置参数为max.in.flight.requests.per.connection,默认值为5。类似于golang中的channel,通道中的未响应请求数量达到5个,将阻塞,当被缓存的未响应请求收到响应,可以继续添加。
生产端的元数据更新
kafka中的元数据:集群中的topic信息,每个topic有哪些分区,每个分区的leader副本分配在哪个节点上,follower副本分配在哪些节点上,具体哪些副本在AR、ISR等集合中,集群中有哪些节点,控制器节点是哪个等信息。
当生产者客户端发送的消息中缺失需要的元数据时(例如未指定topic),或超过metadata.max.age.ms 时间没有更新元数据都会引起元数据的更新操作。默认值为5分钟。元数据的更新是在客户端内部进行的,对外部使用者不可见,也就是开发者不可感知到元数据的更新。当需要更新元数据时,会先挑选出lwastLoaderNode,然后向这个Node发送MetadataRequest请求来获取具体的元数据信息,该操作由Sender发起,在创建完MetadayaRequest之后,会存入InflightRequests,之后的步骤和发送消息类似,元数据的更新虽然由Sender线程负责更新,但是主线程也需要读取这些信息,这里的数据同步通过synchronized和final关键字来保障。
今天也是了解了大概的原理,每个细节都值得去深挖,故写文自勉。
了解Kafka生产者的更多相关文章
- 【转】 详解Kafka生产者Producer配置
粘贴一下这个配置,与我自己的程序做对比,看看能不能完善我的异步带代码: ----------------------------------------- 详解Kafka生产者Produce ...
- Kafka生产者-向Kafka中写入数据
(1)生产者概览 (1)不同的应用场景对消息有不同的需求,即是否允许消息丢失.重复.延迟以及吞吐量的要求.不同场景对Kafka生产者的API使用和配置会有直接的影响. 例子1:信用卡事务处理系统,不允 ...
- Python 使用python-kafka类库开发kafka生产者&消费者&客户端
使用python-kafka类库开发kafka生产者&消费者&客户端 By: 授客 QQ:1033553122 1.测试环境 python 3.4 zookeeper- ...
- Kafka集群安装部署、Kafka生产者、Kafka消费者
Storm上游数据源之Kakfa 目标: 理解Storm消费的数据来源.理解JMS规范.理解Kafka核心组件.掌握Kakfa生产者API.掌握Kafka消费者API.对流式计算的生态环境有深入的了解 ...
- [Spark][kafka]kafka 生产者,消费者 互动例子
[Spark][kafka]kafka 生产者,消费者 互动例子 # pwd/usr/local/kafka_2.11-0.10.0.1/bin 创建topic:# ./kafka-topics.sh ...
- Kafka权威指南 读书笔记之(三)Kafka 生产者一一向 Kafka 写入数据
不管是把 Kafka 作为消息队列.消息总线还是数据存储平台来使用 ,总是需要有一个可以往 Kafka 写入数据的生产者和一个从 Kafka 读取数据的消费者,或者一个兼具两种角色的应用程序. 开发者 ...
- kafka生产者
1.kafka生产者是线程安全的,她允许多个线程共享一个kafka实例 2.kafka管理一个简单的后台线程,所有的IO操作以及与每个broker的tcp连接通信,如果没有正确的关闭生产者可能会造成资 ...
- java实现Kafka生产者示例
使用java实现Kafka的生产者 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 3 ...
- kafka生产者和消费者流程
前言 根据源码分析kafka java客户端的生产者和消费者的流程. 基于zookeeper的旧消费者 kafka消费者从消费数据到关闭经历的流程. 由于3个核心线程 基于zookeeper的连接器监 ...
- JAVA封装消息中间件调用一(kafka生产者篇)
这段时间因为工作关系一直在忙于消息中间件的发开,现在趁着项目收尾阶段分享下对kafka的一些使用心得. kafka的原理我这里就不做介绍了,可参考http://orchome.com/kafka/in ...
随机推荐
- Inheritance and the prototype chain 继承和 原型 链
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain Inherita ...
- GS 原理及破解 《0day安全》
1.原理: 在main函数之前,会调用__security_init_cookie函数(win10,vs2017,release,x86): 进入__security_init_cookie函数内部: ...
- CCCC L3-013. 非常弹的球
题意: 刚上高一的森森为了学好物理,买了一个“非常弹”的球.虽然说是非常弹的球,其实也就是一般的弹力球而已.森森玩了一会儿弹力球后突然想到,假如他在地上用力弹球,球最远能弹到多远去呢?他不太会,你能帮 ...
- HDU - 4405 Aeroplane chess(期望dp)
题意:沿着x轴从0走到大于等于N的某处,每一步的步数由骰子(1,2,3,4,5,6)决定,若恰好走到x轴上某飞行路线的起点,则不计入扔骰子数.问从0走到大于等于N的某处的期望的扔骰子次数. 分析: 1 ...
- zabbix 日志
/var/log/zabbix/ tail -f /var/log/zabbix/zabbix_server.log tail -f /var/log/zabbix/zabbix_agentd.log
- SpringBoot学习(四)——配置文件占位符
RandomValuePropertySource:配置文件中可以使用随机数 ${Random.value} ${random.int}, ${random.long}, ${random.int( ...
- spring boot 生命周期初探
1.MytestApplication package com.gomepay; import org.springframework.boot.Banner; import org.springfr ...
- scala def方法时等号和括号使用说明笔记
scala定义方法时会指定入参和返回类型(无返回类型时对应Unit,即java和C中的void模式). 1.有入参,有返回类型时,scala具有类型推导功能,以下两种表达方式效果一样.但根据scala ...
- 从1到n整数中1的个数
[问题]求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1.10.11.12.13因此共出现6次,但是对于后面问题他就没辙了.A ...
- js 循环与判断语句的几个练习
<script type="text/javascript"> /*1.X3 * 6528 = 3X * 8256 X为一个数字 填入一个数字 使等式成立*/ for ...