了解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 ...
随机推荐
- (java) webdriver 启动firefox driver时,加载firebug的扩展
去网上下载一个firebug.xpi(对应版本, 我的ff是17,可以使用firebug-1.11.4.xpi,最好使用非firefox浏览器下载,不然提示你直接安装到firefox) @Before ...
- 如何生成 SSH keys, 并在 Github 或 Gitlab 等上添加密钥
1 打开 Git Bash $ 2 输入 dir, 确认当前文件夹,并切换到想存密钥文件即pub文件的路径 $ dir 3 生成 密钥命令 ssh-keygen -t rsa -C "{ y ...
- Egret Engine 2D - 显示对象
alpha:透明度 width:宽度 height:高度 rotation:旋转角度 scaleX:横向缩放 scaleY:纵向缩放 skewX:横向斜切 skewY:纵向斜切 visible ...
- 使用node.js安装asar和反编译app.asar
背景:app.asar文件是Electron加密打包时的中间产物,electron.exe调用resources文件夹下的app.asar从而实现不用解压缩而直接读取文件内容的高效. 一.需要先安装n ...
- idea的简单使用
1.新建项目 (1)点击 file -->new project ,选择java(创建普通java项目) ,点next (2)不选择create project from template (不 ...
- 使用模拟器调试react-native步骤(安卓机)
1.在cmd界面搭建react-native 环境: 可参考https://reactnative.cn/docs/0.51/getting-started.html#content (1)npm i ...
- PHP日期函数
在正式学习日期函数前大家得了解几个概念: 1.时区 2.世界时 3.unix时间戳 时区 这个概念,之前大家听说过很多.我们来啰嗦两句,我们现实生活中使用的实区,在电脑里面也是一样有规定的.1884年 ...
- filter滤镜兼容ie的rgba属性
要在一个页面中设置一个半透明的白色div.这个貌似不是难题,只需要给这个div设置如下的属性即可: background: rgba(255,255,255,0.1); 但是要兼容到ie8.这个就有点 ...
- IBGP的自己下一跳,指定源命令。
neighbor router-id update-source loopback int 当两者并不是以物理接口为搭建邻居的时候,就得使用指定源,充当TCP接口. neighbor router-i ...
- Python中的常用内置对象之range对象
range(start, stop[, step]) 可生成满足条件的数.具体来说是返回一个从start开始到小于stop的相邻数的差step的等差数列列表.结果中包含start一直到小于stop的 ...