本篇介绍kafka生产者。
生产者概述
1:生产者:向kafka写入消息。
2:要明确以下定义:
2.1:记录对象:包括 主题、分区、键、值等等。
2.2:序列化器:将键和值序列化为字节数组。
2.3:分区器:根据键来选择分区,并将记录添加到缓冲区。
2.4:缓冲区:存储记录批次。
2.5:发送线程:将记录批次发送到相应的broker。
3:发送过程如下图所示:
创建记录对象–》发送给序列化器–》发送给分区器–》发送给缓存区–》发送broker
生产者组件图:
创建kafka生产者
创建生产者非常简单,代码如下:
1:代码Demo:
Properties kafkaProps = new Properties();
kafkaProps.put(“bootstrap.servers”, “broker1:port1, broker2:port2”);
kafkaProps.put(“key.serializer”, “org.apache.kafka.common.StringSerializer”);
kafkaProps.put(“value.serializer”, “org.apache.kafka.common.StringSerializer”);
producer = new KafkaProducer<String, String>(kafkaProps);
2:关键参数介绍:
2.1:bootstrap.servers:指定broker地址清单,地址格式为host:port。
2.2:key.serializer:键序列化器,将键转换成字节数组。
2.3:value.serializer:值序列化器,将值转换成字节数组。
发送消息到kafka
1:发送方式:
1.1:发送并忘记。
1.2:同步发送。
1.3:异步发送。
2:同步发送消息
2.1:代码如下:
ProducerRecord<String, String> record = new ProducerRecord<>(“CustomCountry”, “Precision Products”, “France”);
try{
Future future = producer.send(record);
future.get();
} catch(Exception e) {
e.printStackTrace();
}
2.2:关键代码说明:
2.2.1:调用send()方法:发送消息,并返回结果-future。
2.2.2:调用get()方法:服务器没发生错误,get()方法会得到一个RecordMetadata对象,包含偏移量、分区。服务器发生错误,get()方法会抛出异常。
2.2.3:两种错误类型: 1:可重发消息来解决,如:链接错误。2:不可重发消息来解决,如:消息太大
3:异步发送消息
3.1:代码如下:
ProducerRecord<String, String> record = new ProducerRecord<>(“CustomCountry”, “Precision Products”, “France”);
producer.send(record, new DemoProducerCallback());
private class DemoProducerCallback implements Callback {
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if (e != null) {
e.printStackTrace();
}
}
}
3.2:关键代码说明:
3.2.1:发送消息时,传递一个回调对象,该回调对象必须实现org.apahce.kafka.clients.producer.Callback接口
3.2.2:如果Kafka返回一个错误,onCompletion方法抛出一个非空(non null)异常
生产者的配置
1:首先明确一点,生产者有很多配置的参数,大部分都是合理的默认值,因此没有必要修改。
2:有几个参数在内存使用,性能和可靠性方面对生产者影响较大。如下:
2.1:acks:指定必须有几个分区副本收到消息,消费者才会认为消息写入是成功的
acks=0:生产者不关心消息是否写入成功
acks=1:只要集群首领收到消息,就代表成功
acks=all:所有参与复制的节点全部收到消息,才代表成功
2.2:buffer.memery:设置生产者缓冲区大小。
2.3:compression.type:压缩类型。snappy,gzip,lz4。
2.3.1:snappy:占用cpu较少,压缩比可观。
2.3.2:gzip:占用cpu较多,压缩比更高。
2.4:retries:生产者可以重发消息的次数。
2.5:batch.size:指定一个批次可以使用内存大小,按照字节数计算(而不是消息个数)。
2.6:linger.ms:指定生产者在发送批次之前等待更多消息加入批次的时间 。
还有一些其他参数,可以查看kafka官方文档。
序列化器
1:序列化器包含两类,一类是自定义序列化器,另一类是使用序列化框架(avro)
2:不建议使用自定义序列化器,因为自定义序列化器存在一下问题:
2.1:兼容性差。
2.2:序列化器发生改变,多个团队都得改。
3:使用avro序列化:
3.1:avro:与编程语言无关的的序列化格式,通过与语言无关的schema来定义
schema:通过Json来描述,如下图所示:
3.2:序列化过程:
将对象进行序列化–》将schema和序列化后的对象放到数据文件中。
3.3:注意点:
3.3.1:写入数据和读取数据的schema必须兼容
3.3.2:反序列化器需要用到用于写入数据的schema
3.4:问题:
3.4.1:schema 和数据放到一起,会增加网络开销
3.5:解决方案:
3.5.1:将schema放入schema注册器,记录里引用schema的标志符
3.5.2:代码如下:
Properties props = new Properties();
props.put(“bootstrap”, “loacalhost:9092”);
props.put(“key.serializer”, “io.confluent.kafka.serializers.KafkaAvroSerializer”);
props.put(“value.serializer”, “io.confluent.kafka.serializers.KafkaAvroSerializer”);
props.put(“schema.registry.url”, schemaUrl);//schema.registry.url指向schema的存储位置
String topic = “CustomerContacts”;
Producer<String, Customer> produer = new KafkaProducer<String, Customer>(props);
while (true) {//不断生成消息并发送
Customer customer = CustomerGenerator.getNext();
ProducerRecord<String, Customer> record = new ProducerRecord<>(topic, customer.getId(), customer);
producer.send(record);//将customer作为消息的值发送出去,KafkaAvroSerializer会处理剩下的事情
}
3.5.3:结构图如下所示:
分区
分区有如下几种方式:
以上就是生产者的相关内容,哪里说错了,还请见谅。