kafka 生产者
-
kafka 发送数据流程
kafka 发送数据分两个线程,主线程和sender线程,在我们使用KafkaProducer的就会帮我们实例化一个sender线程(kafka-producer-network-thread|加clientId)
主线程:由KafkaProducer创建消息,经过拦截器、序列化器、分区器,负责发送数据到RecordAccumulator,然后缓存消息,以便sender可以批量发送。RecoredAccumulator里面会为每个分区维护一个双端队列Deque<ProducerBatch》,消息写入缓存,就是将数据追加到这个双端队列的末尾。ProducerBatch里面包含一个或者多个ProducerRecord,ProducerRecord是创建的消息,ProducerBath是一个消息批次,这样会使消息更加紧凑,减少网络请求增加吞吐量。
sender线程:从RecordAccumulator双端队列的头部读取数据。从PartitionInfo中读取相应partition对象的Node节点,在集群Cluster中获取已经准备好的Node节点(集群中的broker节点),将数据封装到Map<Integer, List<ProducerBatch》>数据中。会按照Node,还有ack,transactionalId把数据封装到ProduceRequest中,这样每个节点就会对应一个request,就可以把这个request发送到对应的节点。会去调用KafkaClient.send()来发送数据,在发送之前会把request封装到InFlightRequest,然后加到一个双端队列Deque<NetworkClient.InFlightRequest>中,最后把数据交给selector去发送。
-
kafka器件
1、我们可以增加自定义的拦截器,为我们数据格式化或者加指定的头
ProducerRecord<K, V> interceptedRecord = this.interceptors.onSend(record); return doSend(interceptedRecord, callback);
public class ProducerInterceptorCustom implements ProducerInterceptor<String, String> { @Override public ProducerRecord onSend(ProducerRecord record) { return new ProducerRecord(record.topic(), record.partition(), record.key(), "prefix" + record.value()); } } //指定 拦截器 properties.setProperty(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, ProducerInterceptorCustom.class.getName());
2、自定义序列化器
kafka提供了多种序列化器,StringSerializer、ByteBufferSerializer、BytesSerializer等多种序列化,我们还可以选择Avro、JSON、Thrift、ProtoBuf和ProtoSuff等序列化工具来实现。发送使用序列化,消费的时候使用反序列化得到我们发送的数据。
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class); props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, ByteBufferDeserializer.class);
3、分区器
发送数据之前会指定我们数据发送到哪个partition,如果指定分区就发送到指定的分区,如果没有指定,如果key不为空,就采用MurmurHash2算法(高运算性能低碰撞率),hash值来计算分区;如果key为空,采用轮询的方式发送到各个分区。kafka分区内的数据是有序的,但是不同分区的数据是不能保证有序的,如果要保证数据有序,可以配置key使数据发送到同一个分区。
//自定义分区器 properties.setProperty(ProducerConfig.PARTITIONER_CLASS_CONFIG, ProducerPartitionCustom.class.getName());
-
重要参数理解
1、acks
他是生产者发送数据可靠性和吞吐量的权衡
acks = 1 只要分区的leader接受数据并且成功写入,就会来自服务端的成功访问。可靠性和吞吐量的折中方案。
acks = 0 生产者发送数据,不需要等待任何的服务器相应,这种情况下吞吐量最大,但是中间出现异常却不知道。
acks = -1或者all 发送数据之后,需要所有的ISR都成功写入,才会来自服务端的成功响应。可以达到高可靠性。
2、reties
生产者重试的次数,默认值是0,消息从生产者写入到服务器,可能会出现一些异常,比如网络抖动、leader选举,这一些异常是可以恢复,通过内部重试可以恢复数据,但是有一些异常是不能通过重试来恢复的,比如说消息太大,需要把异常抛到应用程序来处理。重试次数一般和retry.backoff.ms重试间隔时间同步使用。
3、max.request.size
最大客户端能发送消息的最大值。
4、compression.type
producer是否需要压缩消息,默认none。压缩消息可以减少网络消息传输从而提升吞吐量,但也会增加cpu的负担。目前kafka支持GZIP、snappy和LZ4压缩算法。