前言
本文隶属于专栏《1000个问题搞定大数据技术体系》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢!
本专栏目录结构和参考文献请见1000个问题搞定大数据技术体系
正文
Producer 标准模范代码
package com.shockang.study.bigdata.kafka.clients;
import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.errors.RetriableException;
import java.util.Properties;
public class MyProducer {
public static void main(String[] args) throws Exception {
Properties props = new Properties();
// 必须指定 集群的连接地址,最好多个地址
props.put("bootstrap.servers", "localhost:9092");
// 必须指定 Key 的序列化器
props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// 必须指定 value 的序列化器
props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// 在请求完成之前,Producer 要求 Leader 收到的确认数。这将控制发送的记录的持久性。
props.put("acks", "-1");
// 设置一个大于零的值将导致客户端重新发送其发送失败的任何记录
props.put("retries", "3");
// 每当多个记录被发送到同一分区时,生产者将尝试将记录批处理到一起,以减少请求。此配置控制以字节为单位的默认批处理大小。
props.put("batch.size", "323840");
// 一旦我们得到一个分区的batch.size值的记录,不管这个设置如何,它都会被立即发送,但是如果这个分区的累积字节数少于这个字节数,我们将“逗留”指定的时间,等待更多的记录出现
props.put("linger.ms", "10");
// Producer 可以用来缓冲等待发送到服务器的记录的总内存字节数
props.put("buffer.memory", "33554432");
// 此超时限制等待元数据获取和缓冲区分配的总时间
props.put("max.block.ms", "3000");
Producer<String, String> producer = new KafkaProducer<>(props);
for (int i = 0; i < 100; i++) {
// 推荐使用带 Callback 的 send 方法
producer.send(new ProducerRecord<>("my-topic", Integer.toString(i), Integer.toString(i)), new Callback() {
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
// 可以准确提示消息发送成功,发送失败可以通过 e 来针对处理
if (e == null) {
System.out.println("Send record succeed!");
} else {
System.out.println("Send record failed!");
if(e instanceof RetriableException){
// 处理可重试异常
}else{
// 处理不可重试异常
}
}
}
});
}
producer.close();
}
}
Consumer 标准模范代码
package com.shockang.study.bigdata.kafka.clients;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.common.PartitionInfo;
import org.apache.kafka.common.TopicPartition;
import org.apache.kafka.common.errors.WakeupException;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
public class MyConsumer {
public static void main(String[] args) {
Properties props = new Properties();
// 集群连接地址
props.put("bootstrap.servers", "localhost:9092");
// 如果Kafka中没有初始偏移量,或者服务器上不再存在当前偏移量(例如,因为该数据已被删除),该怎么办:earliest-自动将偏移量重置为最早偏移量
props.put("auto.offset.reset", "earliest");
// 如果为真,Consumer 的 offset 将定期在后台提交。
props.put("enable.auto.commit", "false");
// key 的反序列化器
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
// value 的反序列化器
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
List<TopicPartition> partitions = new ArrayList<>();
List<PartitionInfo> allPartitions = consumer.partitionsFor("my-topic");
if (allPartitions != null && !allPartitions.isEmpty()) {
for (PartitionInfo partitionInfo : allPartitions) {
partitions.add(new TopicPartition(partitionInfo.topic(), partitionInfo.partition()));
}
consumer.assign(partitions);
}
try {
for (; ; ) {
// poll(long) 已经 deprecated,现在推荐使用 poll(Duration)
ConsumerRecords<String, String> records = consumer.poll(Duration.of(Long.MAX_VALUE, ChronoUnit.MILLIS));
for (ConsumerRecord<String, String> record : records) {
System.out.println(String.format("topic=%s,partition=%d,offset=%d", record.topic(), record.partition(), record.offset()));
// / 使用异步提交规避阻塞
consumer.commitAsync();
}
}
} catch (WakeupException e) {
e.printStackTrace();
} finally {
// 最后一次提交使用同步阻塞式提交
consumer.commitSync();
consumer.close();
}
}
}