:fire:《Kafka运维管控平台LogiKM》:fire: :pencil2:更强大的管控能力:pencil2: :tennis:更高效的问题定位能力:tennis: :sunrise:更便捷的集群运维能力:sunrise: :musical_score:更专业的资源治理:musical_score: :sun_with_face:更友好的运维生态:sun_with_face:
@[TOC] 今天我们来通过源码来分析一下,生产者发送一条消息的所有流程~~~
生产者客户端代码
public class SzzTestSend { public static final String bootStrap = "xxxxxx:9090"; public static final String topic = "t_3_1"; public static void main(String[] args) { Properties properties = new Properties(); properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,bootStrap); // 序列化协议 下面两种写法都可以 properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class.getName()); properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer"); //过滤器 可配置多个用逗号隔开 properties.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG,"org.apache.kafka.clients.producer.SzzProducerInterceptorsTest"); //构造 KafkaProducer KafkaProducer producer = new KafkaProducer(properties); // 发送消息, 并设置 回调(回调函数也可以不要) ProducerRecordrecord = new ProducerRecord(topic,"Hello World!"); try { producer.send(record,new SzzTestCallBack(record.topic(), record.key(), record.value())); }catch (Exception e){ e.printStackTrace(); } } /** * 发送成功回调类 */ public static class SzzTestCallBack implements Callback{ private static final Logger log = LoggerFactory.getLogger(SzzTestCallBack.class); private String topic; private String key; private String value; public SzzTestCallBack(String topic, String key, String value) { this.topic = topic; this.key = key; this.value = value; } public void onCompletion(RecordMetadata metadata, Exception e) { if (e != null) { log.error("Error when sending message to topic {} with key: {}, value: {} with error:", topic, key,value, e); }else { log.info("send message to topic {} with key: {} value:{} success, partiton:{} offset:{}", topic, key,value,metadata.partition(),metadata.offset()); } } } } 复制代码
KafkaProducer通过解析 producer.propeties
文件里面的属性来构造自己。 例如 :分区器、Key和Value序列化器、拦截器、 RecordAccumulator消息累加器 、元信息更新器、启动发送请求的后台线程
//构造 KafkaProducer KafkaProducer producer = new KafkaProducer(properties); 复制代码
我们之前有讲过. 客户端都会保存集群的元信息,例如生产者的元信息是 ProducerMetadata. 消费组的是ConsumerMetadata 。
元信息都会有自己的自动更新逻辑, 详细请看 Kafka的客户端发起元信息更新请求
相关的Producer配置有:
属性 | 描述 | 默认 |
---|---|---|
metadata.max.age.ms | 即使我们没有看到任何分区领导层更改以主动发现任何新代理或分区,我们也强制刷新元数据的时间段(以毫秒为单位)。。 | 300000(5分钟) |
retry.backoff.ms | 如果上次更新失败,发起重试的间隔时间 | 100 |
虽然Producer元信息会自动更新, 但是有可能在生产者发送消息的时候,发现某个TopicPartition不存在,这个时候可能就需要立刻发起一个元信息更新了。
生产者拦截器在消息发送之前可以做一些准备工作, 比如 按照某个规则过滤某条消息, 又或者对 消息体做一些改造, 还可以用来在发送回调逻辑之前做一些定制化的需求,例如统计类的工作! 拦截器的执行时机在最前面,在 消息序列化 和 分区计算 之前
相关的Producer配置有:
属性 | 描述 | 默认 |
---|---|---|
interceptor.classes | 生产者拦截器配置,填写全路径类名,可用逗号隔开配置多个,执行顺序就是配置的顺序。 | 空 |
用来设置发送的消息具体要发送到哪个分区上
相关的Producer配置有:
属性 | 描述 | 默认值 |
---|---|---|
partitioner.class | 消息的分区分配策略 | org.apache.kafka.clients.producer.internals.DefaultPartitioner |
Sender是专门负责将消息发送到Broker的I/O线程。
相关的Producer配置有:
属性 | 描述 | 默认值 |
---|---|---|
max.in.flight.requests.per.connection | 客户端能够允许的最大未完成请求(在请求中)的请求数量, 如果该值大于1, 并且请 |