Kafka之Producer生产者

Kafka生产者的消息对象定义:
Kafka之Producer生产者_第1张图片

  • topic:主题名称
  • partition:指定的分区号
  • headers:消息头部,一般不用指定。
  • key:用来指定消息的键,它不仅仅是消息附加信息,可以通过它来计算分区号来发往指定分区。topic对消息进行归类,key可以对消息进行二次归类。
  • value:消息体。如果消息体为空,则称为墓碑消息。
  • timestamp:时间戳,它有两种类型,CreateTime和LogAppendTime,分别是消息创建时间和消息追加到日志文件的时间 。

必要参数配置

在创建生产者时需要配置一些参数的,比如需要连接的Kafka集群地址等。

  • bootstarp.servers:用来指定kafka集群地址。格式host1:port1,host2:port2。并不需要配置所有broker地址,生成者会从指定的broker中找到其他broker信息,建议至少配置2台。
  • key.serializer和value.serializer:broker端接收的消息必须是byte字节数组形式。key.serializer和value.serializer分别指定key和value序列化时的序列化器。
  • client.id:非必填。指定客户端id,不填会自动生成。

发送消息的三种方式

1.发后即忘、2.同步、3.异步。
我们看下异步方式:可以传入一个Callback对象,有响应是会回调或者抛出异常。
红圈中,两者只有一个值为null。
在这里插入图片描述
发后既忘:直接调用send方法,不会对返回值进行其他操作。

同步:既然是Future类型,那么get方法是阻塞直到获取返回结果。可以看到KafkaProducer的send方法返回都是Future类型。RecprdMetadata可获得主题、分区号、偏移量、时间戳等等。
Kafka之Producer生产者_第2张图片
同步编程方式
Kafka之Producer生产者_第3张图片

序列化器

生产者需要用序列化器将对象转为字节数组发送到网络中,消费者需要用反序列化器将字节数组转为相应的对象。
Serializer接口的相关实现类
Kafka之Producer生产者_第4张图片
接口中的方法
Kafka之Producer生产者_第5张图片
建议:序列化和反序列化,最好使用JSON、thrift、protobuf等成熟的序列化协议。

分区器

Kafka默认提供的分区器是DefaultPartitioner.java。如果key不为null,那么会进行hash计算,用哈希值来计算分区号。如果key为null,会轮询发往topic内的各个分区。如果新增分区,那么key不再会映射到原来分区上。

生产者拦截器

生产者拦截器可以用来在消息发送前做一些准备工作,过滤不符合的消息、修改消息、发送回调逻辑前做一些定制需求,比如统计。

发送流程

kafka由两个线程协调运行,分别是主线程和Sender线程(发送线程)。主线程由KafkaProducer创建消息,可能通过拦截器、序列化器、分区器,最后进入消息累加器RecordAccumulator。Sender线程从消息累加器中获取消息发往kafka。

RecordAccumulator消息累加器主要用来缓存消息以便Sender线程批量发送消息。

每个分区都维护一个双端队列。队列内容为ProducerBatch。消息写入到双端队列尾部,读取从头部。ProducerBatch中可以包含一个或者多个ProducerRecord。

消息在网络上都是以字节形式传输的,发送之前需要创建一块内存区域来保存对应的消息。为了防止频繁的创建和释放ByteBuffer,RecordAccumulator里有一个BufferPool,它只针对特定大小的ByteBuffer进行管理,其他大小的ByteBuffer不会缓存进去。通过batch.size来指定特定大小。

当一条消息ProducerRecord流入RecordAccumulator消息累加器时,会寻找与消息分区对应的双端队列(如果没有则新建),再从双端队列尾部取出ProducerBatch(如果没有则新建),查看ProdcuerBatch是否还可以写入这一条消息,可以写入则不用创建新的。在新建ProducerBatch时,会评估这条消息是否超过了batch.size参数大小,如果没有超过,就以batch.size的参数大小创建ProducerBatch,可以通过BufferPool来进行管理复用。

Sender从RecordAccumulator中获取缓存的消息后,会将原本的<分区,Deque>保存形式转变为,Node表示Kafka集群的broker节点。对于网络连接来说,生产者客户端与具体的broker节点进行连接,并不关心消息属于哪个分区。对于KafkaProducer应用逻辑来说,只关心向哪个分区发送消息。这里做了一个应用逻辑到网络IO层面转换。

转换后,Sender再次转为形式,Request指kafka各种协议请求。

请求从Sender线程发往Kafka之前还会保存到InFlightRequest中,主要是缓存已经发送出去但还没收到响应的请求。通过配置参数max.in.flight.requests.per.connection可以现在每个链接最多缓存的请求数。超过后,不能再向这个连接发送更多的请求。
Kafka之Producer生产者_第6张图片
元数据更新
首先要知道LeastLoadedNod:即所有Node中负载最小的那一个。负载最小是通过每个Node在InFlightRequest中还未确认的请求决定的。可以看到Node1是。

LeastLoadedNode可应用于多个场合,比如元数据请求、消费者组播协议的交互。

元数据是指Kafka集群的元数据,这些元数据记录了集群中有哪些主题,这些主题有哪些分区,每个分区的leader副本在哪个节点上,follower副本分配在哪些节点上,哪些副本在ISR、AR等集合中,集群中有哪些节点,控制器节点又是哪一个等信息。

当需要更新元数据信息时,会挑选出来LeastLoadedNode,然后向这个Node发送MetaRequest请求具体的元数据信息。更新操作由Sender发起,创建完MetaRequest后同样存入InFlightRequests中。主线程需要读取这些信息,数据同步通过Synchronized和final关键字保障。

Kafka之Producer生产者_第7张图片

你可能感兴趣的:(Kafka)