Kafka生产者producer简要总结

Kafka producer在设计上要比consumer简单,不涉及复杂的组管理操作,每个producer都是独立进行工作的,与其他producer实例之间没有关联。Producer的主要功能就是向某个topic的某个分区发送消息,所以首先要确认向topic的哪个分区写入消息——即分区器(partitioner)的功能。Kafka producer提供了一个默认的分区器。对于每条待发送的消息而言,如果该消息指定了key,则partitioner会根据key的哈希值来选择目标分区,将具有相同key的所有消息都路由到相同的分区中;若该消息未指定key,则partitioner使用轮询的方式确认目标分区。另外producer的API赋予了用户自行指定目标分区的权力,即用户可以在消息发送时跳过partitioner直接指定到要发送到的分区。

另外producer也允许用户实现自定义的分区策略而非使用默认的partitioner。

确认分区后,producer要做的第二件事是寻找该分区对应的leader,也就是该分区leader副本所在的Kafka broker。每个topic分区都由若干个副本组成,其中一个副本充当leader角色,只有leader能响应clients发送的请求,剩下的副本中有一部分副本会与leader副本保持同步,即所谓的ISR(In-Sync Replicas, 副本同步队列)。因此,在发送消息时,producer可以有多种选择来实现消息发送,例如不等待任何副本的响应便返回成功,或者只是等待leader副本响应写入操作后再返回成功。

补充副本概念:

副本(Replication)

同一个partition可能会有多个replication(对应server.properties 配置中的 default.replication.factor=N)。没有replication的情况下,一旦broker 宕机,其上所有 patition 的数据都不可被消费,同时producer也不能再将数据存于其上的patition。引入replication之后,同一个partition可能会有多个replication,而这时需要在这些replication之间选出一个leader,producer和consumer只与这个leader交互,其它replication作为follower从leader 中复制数据。

Producer写入流程

1)producer先从zookeeper的 “/brokers/…/state”节点找到该partition的leader

2)producer将消息发送给该leader

3)leader将消息写入本地log

4)followers从leader pull消息,写入本地log后向leader发送ACK

5)leader收到所有ISR中的replication的ACK后,增加HW(high watermark,最后commit 的offset)并向producer发送ACK

Producer发送消息

在Java版代码中,producer首先使用一个线程(用户主线程,也就是用户启动producer的线程)将待发送的消息封装进一个ProducerRecord类实例,然后将其序列化之后发送给partitioner,再由后者确定了目标分区后一同发送到位于producer程序中的一块内存缓冲池中。而producer的另一个工作线程(I/O发送线程,也称Sender线程)则负责实时地从该缓冲区中提取准备就绪的消息封装进一个批次(batch),统一发送给对应的broker。

Kafka producer发送消息的主方法是send方法,producer在底层完全实现了异步化发送,并且通过Java提供的Future同时实现了同步发送和异步发送+回调(Callback)(默认异步)两种发送方式。最后producer程序结束时需要关闭producer。

acks参数(用来平衡吞吐量与可靠性):

producers可以一步的并行向kafka发送消息,但是通常producer在发送完消息之后会得到一个响应,返回的是offset值(metadata)或者发送过程中遇到的错误(exception)。这其中有个非常重要的参数“request.required.acks”,这个参数决定了producer要求leader partition收到确认的副本个数:

如果acks设置为0,表示producer不会等待broker的响应,所以,producer无法知道消息是否发生成功,这样有可能导致数据丢失,但同时,acks值为0会得到最大的系统吞吐量。一般这种情况下允许消息丢失,如统计服务器日志等;

若acks设置为1,表示producer会在leader partition收到消息时得到broker的一个确认,这样会有更好的可靠性,因为客户端会等待知道broker确认收到消息。此时,当发送消息时,leader broker仅将该消息写入本地日志,然后便发送响应结果给producer,而无需等待ISR中其他副本写入该消息;

若设置为-1或者all,producer会在所有备份的partition收到消息时得到broker的确认,这个设置可以得到最高的可靠性保证。此时,当发送消息时,leader broker不仅会将消息写入本地日志,同时还会等待ISR中所有其他副本都成功写入它们各自的本地日志后,才发送响应结果给producer。

buffer.memory参数:

指定producer端用于缓存消息的缓冲区的大小,单位是字节,默认32M,采用异步发送消息的架构,Java版Producer启动时会首先创建一块内存缓冲区用于保存待发送消息,然后由另一个专属线程负责从缓冲区中读取消息执行真正的发送,这部分内存空间的大小就是由buffer.memory参数指定。该参数指定的内存大小几乎可以认为是producer程序使用的内存大小,若producer程序要给很多分区发送消息,那么就需要仔细设置该参数防止过小的内存缓冲区降低了producer程序整体的吞吐量。

batch.size参数:

batch.size是producer调优吞吐量与延时性能最重要的参数之一,producer会将发往同一分区的多条消息封装进一个batch中,当batch满了或者batch没满(linger.ms参数=0,默认消息立即发送)producer会发送该batch。

Batch小,吞吐量低,延时低,Batch大,吞吐量高,延时高

Batch.size默认为16KB。

request.timeout.ms参数:

当producer发送请求给broker后,broker需要在规定时间范围内将处理结果返回给producer。超时时间默认30s。

自定义分区机制

  1. 在producer程序中创建一个类,实现org.apache.kafka.clients.producer.Partitioner接口,主要分区逻辑在Partitioner.partition中实现。入参(topic, key, keyBytes, value, valueBytes, Cluster);
  2. 在用于构造KafkaProducer的Properties对象中设置partitioner.class参数。

序列化

网络上发送数据都是以字节的形式,kafka也不例外,Apache Kafka支持用户给broker发送各种类型消息,如字符串、整数、数组或任意对象类型,序列化器serializer负责在producer发送前将消息转换成字节数组;解序列化器deserializer则用于将consumer接收到的字节数组转换成相应的对象。

猜你喜欢

转载自www.cnblogs.com/csuliujia/p/10006611.html
今日推荐