文章目录
- 4. Kafka API
- 4.1 Producer API
- 4.1.1 消息发送流程
- 4.1.2 异步发送 API
- 4.2 Consumer API
- 4.3 手动异步提交offset
- 总结
4. Kafka API
4.1 Producer API
4.1.1 消息发送流程
Kafka 的 Producer 发送消息采用的是异步发送的方式。在消息发送的过程中,涉及到了 两个线程——main 线程和 Sender 线程,以及一个线程共享变量——RecordAccumulator。 main 线程将消息发送给 RecordAccumulator,Sender 线程不断从 RecordAccumulator 中拉取 消息发送到 Kafka broker。
相关参数:
batch.size:只有数据积累到 batch.size 之后,sender 才会发送数据。
linger.ms:如果数据迟迟未达到 batch.size,sender 等待 linger.time 之后就会发送数据。
4.1.2 异步发送 API
导入依赖:
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>0.11.0.0</version>
</dependency>
- 不带回调函数的 API:
import org.apache.kafka.clients.producer.*;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
public class CustomProducer1 {
public static void main(String[] args) throws ExecutionException, InterruptedException{
Properties props = new Properties();
/** 也可以用ProducerConfig类进行参数配置,用这种方法的较多
* //kafka集群
* props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG, "hadoop102:9092");
* //ack应答级别
* props.put(ProducerConfig.ACKS_CONFIG, "all");
*
* //重试次数
* props.put(ProducerConfig.RETRIES_CONFIG, 1);
* //批次大小,16k
* props.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);
* //等待时间,1ms
* props.put(ProducerConfig.LINGER_MS_CONFIG, 1);
* //RecordAccumulator 缓冲区大小,32M
* props.put(ProducerConfig.BUFFER_MEMORY_CONFIG, 33554432);
*/
//kafka集群
props.put("bootstrap.servers", "hadoop102:9092");
//ack应答级别
props.put("ack", "all");
//重试次数
props.put("retries", 1);
//批次大小,16k
props.put("batch.size", 16384);
//等待时间,1ms
props.put("linger.ms", 1);
//RecordAccumulator 缓冲区大小,32M
props.put("buffer.memory", 33554432);
//key,value的序列化类
props.put("key.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
//创建生产者对象
Producer<String, String> producer = new KafkaProducer<>(props);
for (int i = 0; i < 10; i++) {
producer.send(new ProducerRecord<>("first",
"测试数据--" + i));
}
//关闭资源
producer.close();
}
}
在kafka集群上启动一个代码中对应的消费者:
- 带回调函数的 API:
package com.tianyi.kafka.producer;
import org.apache.kafka.clients.producer.*;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
/**
* CustomProducer2
* 带回调函数
* @author hutianyi
* @date 2022/6/6
**/
public class CustomProducer2 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
Properties props = new Properties();
props.put("bootstrap.servers", "hadoop102:9092");//kafka 集群,broker-list
props.put("acks", "all");
props.put("retries", 1);//重试次数
props.put("batch.size", 16384);//批次大小
props.put("linger.ms", 1);//等待时间
props.put("buffer.memory", 33554432);//RecordAccumulator 缓冲区大小
props.put("key.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
Producer<String, String> producer = new
KafkaProducer<>(props);
for (int i = 0; i < 10; i++) {
producer.send(new ProducerRecord<>("first",
"测试数据---" + i), new Callback() {
//回调函数,该方法会在 Producer 收到 ack 时调用,为异步调用
@Override
public void onCompletion(RecordMetadata metadata,
Exception exception) {
if (exception == null) {
System.out.println(metadata.partition() + "---" + metadata.offset());
} else {
exception.printStackTrace();
}
}
});
}
producer.close();
}
}
控制台输出:
4.2 Consumer API
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.util.Arrays;
import java.util.Properties;
public class CustomConsumer1 {
public static void main(String[] args) {
//创建消费者配置信息
Properties props = new Properties();
//连接的集群
props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, "hadoop102:9092");
//消费者组
props.put(ConsumerConfig.GROUP_ID_CONFIG, "bigdata");
//开启自动提交
props.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "true");
//自动提交的延时
props.put(ConsumerConfig.AUTO_COMMIT_INTERVAL_MS_CONFIG, "1000");
//key,value的反序列化
props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,
"org.apache.kafka.common.serialization.StringDeserializer");
props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,
"org.apache.kafka.common.serialization.StringDeserializer");
// //重置消费者的offset
// props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
//创建消费者
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
//订阅主题
consumer.subscribe(Arrays.asList("first"));
//获取数据
while (true) {
ConsumerRecords<String, String> records = consumer.poll(100);
//解析并打印
for (ConsumerRecord<String, String> record : records){
System.out.printf("offset = %d, key = %s, value = %s%n",
record.offset(), record.key(), record.value());
}
}
}
}
用4.1作为生产者去消费数据:加一个key的参数
producer.send(new ProducerRecord<>("first", "tianyi", "测试数据--" + i));
**重置消费者的offset后,可以将历史数据都消费到,但是必须得修改组名。**即要消费到所有的历史数据,需要满足两个条件:
(1)props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest"); //将offset设置为earliest
(2)props.put(ConsumerConfig.GROUP_ID_CONFIG, "xxxx"); //修改这个组名
4.3 手动异步提交offset
import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.TopicPartition;
import java.util.Arrays;
import java.util.Map;
import java.util.Properties;
public class CustomConsumer3 {
public static void main(String[] args) {
Properties props = new Properties();
//Kafka 集群
props.put("bootstrap.servers", "hadoop102:9092");
//消费者组,只要 group.id 相同,就属于同一个消费者组
props.put("group.id", "test");
//关闭自动提交 offset
props.put("enable.auto.commit", "false");
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList("first"));//消费者订阅主题
while (true) {
ConsumerRecords<String, String> records = consumer.poll(100);//消费者拉取数据
for (ConsumerRecord<String, String> record : records) {
System.out.printf("offset = %d, key = %s, value = %s%n",
record.offset(), record.key(), record.value());
}
//异步提交
consumer.commitAsync(new OffsetCommitCallback() {
@Override
public void onComplete(Map<TopicPartition,
OffsetAndMetadata> offsets, Exception exception) {
if (exception != null) {
System.err.println("Commit failed for" + offsets);
}
}
});
}
}
}
总结
本文介绍了kafka0.11版本生产者和消费者使用的基本API,新版本提供了更加丰富的API,但是使用方式大致是类似的,可以对照官网使用新版本的kafka版本和API,另外,对于kafka集群的参数一般都是使用ProducerConfig / ConsumerConfig去设定的,本文中的部分示例用的是参数名的形式,两种都是可以的,推荐使用配置类去设置参数。