一 kafka发送消息流程
1.1 发送流程原理
kafka在发送消息的过程中,主要涉及两个线程main 线程和 Sender 线程。
在 main 线程 中创建了一个双端队列 RecordAccumulator。main 线程将消息发送给 RecordAccumulator。
1.2 发送信息的时机
生产者何时向broker中发送信息。触发什么机制开始发送呢?这里有两种机制
1.batch.size:数据累计到batch.size之后,sender才会发送数据。
2.linger.ms:如果数据迟迟未达到batch.size,但是设置的linger.ms时间满足条件,则就进行发送数据,单位未ms,默认值是0ms;表示没有延迟。
1.3 生产者需要的配置参数说明
二 代码实操
2.1 异步演示发送代码
package com.ljf.spring.boot.demo.producer;
import com.ljf.spring.boot.demo.utils.DateUtils;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import java.util.Date;
import java.util.Properties;
/**
* @ClassName: producer
* @Description: TODO
* @Author: liujianfu
* @Date: 2022/04/06 17:02:52
* @Version: V1.0
**/
public class producer {
public static void main(String[] args) {
// 1. 创建 kafka 生产者的配置对象
Properties properties = new Properties();
// 2. 给 kafka 配置对象添加配置信息:bootstrap.servers
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,
"192.168.152.136:9092,192.168.152.138:9092,192.168.152.140:9092");
// key,value 序列化(必须):key.serializer,value.serializer
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
"org.apache.kafka.common.serialization.StringSerializer");
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
"org.apache.kafka.common.serialization.StringSerializer");
// 3. 创建 kafka 生产者对象
KafkaProducer<String, String> kafkaProducer = new KafkaProducer<String, String>(properties);
// 4. 调用 send 方法,发送消息
for (int i = 100; i < 105; i++) {
String v="kfdemo-xx"+i+"时间:"+DateUtils.dateToStr(new Date(),"yyyy-MM-dd HH:mm:ss");
kafkaProducer.send(new ProducerRecord<>("kafka-ljf",v));
}
// 5. 关闭资源
kafkaProducer.close();
System.out.println("执行完毕!!!");
}
}
2.启动consumer端
[root@localhost kafka_2.12-2.1.0]# bin/kafka-console-consumer.sh --from-beginning --topic kafka-ljf --bootstrap-server 192.168.152.136:9092,192.168.152.138:9092,192.168.152.140:9092
3.查看consumer的消费情况
2.2 带回调函数的异步发送
package com.ljf.spring.boot.demo.producer;
import com.ljf.spring.boot.demo.utils.DateUtils;
import org.apache.kafka.clients.producer.*;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Date;
import java.util.Properties;
/**
* @ClassName: CustomProducerCallback
* @Description: TODO
* @Author: liujianfu
* @Date: 2022/04/06 18:02:17
* @Version: V1.0
**/
public class CustomProducerCallback {
public static void main(String[] args) throws InterruptedException {
// 1. 创建 kafka 生产者的配置对象
Properties properties = new Properties();
// 2. 给 kafka 配置对象添加配置信息
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,
"192.168.152.136:9092,192.168.152.138:9092,192.168.152.140:9092");
// key,value 序列化(必须):key.serializer,value.serializer
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
StringSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
StringSerializer.class.getName());
// 3. 创建 kafka 生产者对象
KafkaProducer<String, String> kafkaProducer = new
KafkaProducer<String, String>(properties);
// 4. 调用 send 方法,发送消息
for (int i = 0; i < 10; i++) {
// 添加回调
String info="callback-xx"+i+" 时间为:"+DateUtils.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss");
kafkaProducer.send(new ProducerRecord<>("kafka-ljf",info), new Callback() {// 该方法在 Producer 收到 ack 时调用,为异步调用
@Override
public void onCompletion(RecordMetadata metadata,
Exception exception) {
if (exception == null) {
// 没有异常,输出信息到控制台
System.out.println(" 主题: " +
metadata.topic() + "->" + "分区:" + metadata.partition());
} else {
// 出现异常打印
exception.printStackTrace();
}
}
});
// 延迟一会会看到数据发往不同分区
Thread.sleep(2000);
}
// 5. 关闭资源
kafkaProducer.close();
}
}
2.启动消费端
2.3 同步发送数据
1.代码
package com.ljf.spring.boot.demo.producer;
import com.ljf.spring.boot.demo.utils.DateUtils;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.serialization.StringSerializer;
import java.util.Date;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
/**
* @ClassName: CustomProducerSync
* @Description: TODO
* @Author: liujianfu
* @Date: 2022/04/06 18:07:34
* @Version: V1.0
**/
public class CustomProducerSync {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1. 创建 kafka 生产者的配置对象
Properties properties = new Properties();
// 2. 给 kafka 配置对象添加配置信息
properties.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"192.168.152.136:9092,192.168.152.138:9092,192.168.152.140:9092");
// key,value 序列化(必须):key.serializer,value.serializer
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,
StringSerializer.class.getName());
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,
StringSerializer.class.getName());
// 3. 创建 kafka 生产者对象
KafkaProducer<String, String> kafkaProducer = new
KafkaProducer<String, String>(properties);
// 4. 调用 send 方法,发送消息
for (int i = 0; i < 10; i++) {
// 异步发送 默认
// kafkaProducer.send(new ProducerRecord<>("first","kafka" + i));
// 同步发送,只需在异步发送的基础上,再调用一下 get()方法即可。
String info="tonbu-xx"+i+" 时间为:"+ DateUtils.dateToStr(new Date(), "yyyy-MM-dd HH:mm:ss");
kafkaProducer.send(new ProducerRecord<>("kafka-ljf",info)).get();
}
// 5. 关闭资源
kafkaProducer.close();
System.out.println("jieshu");
}
}
2.启动消费者脚本
[root@localhost kafka_2.12-2.1.0]# bin/kafka-console-consumer.sh --from-beginning --topic kafka-ljf --bootstrap-server 192.168.152.136:9092,192.168.152.138:9092,192.168.152.140:9092
3.查看消费结果