不啰嗦,直接上代码(下面是个完整的生产者实例):
package com.z.kafka;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.slf4j.Logger;
public class ProducerUtil {
private static ProducerUtil instance = null;
private KafkaProducer producer;
public static final String SERIALIZER = "org.apache.kafka.common.serialization.StringSerializer";
public ProducerUtil() {
Properties props = new Properties();
props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,"127.0.0.1:9092");// 集群地址
props.put(ProducerConfig.ACKS_CONFIG, "all");// 请求被认为已完成的标准,all:响应阻塞完整提交。性能上不是最好的选择,但却是最稳的。
props.put(ProducerConfig.RETRIES_CONFIG, 1);// 失败尝试提交次数
props.put(ProducerConfig.BATCH_SIZE_CONFIG, 16384);// 批量提交大小
props.put(ProducerConfig.LINGER_MS_CONFIG, 1);// 未成批等待提交毫秒数
props.put(ProducerConfig.CLIENT_ID_CONFIG, "client_test");// 发送客户端id身份标识,追查数据来源时比较有用。
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, SERIALIZER);// 序列化器
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, SERIALIZER);// 序列化器
// 客户端jar版本kafka-clients-0.11.0.1.jar
this.producer = new KafkaProducer(props);
}
public static synchronized ProducerUtil getInstance() {
if (instance == null) {
instance = new ProducerUtil();
System.out.println("初始化 kafka producer...");
}
return instance;
}
// 单条发送
public void send(ProducerRecord msg) {
producer.send(msg);
}
public void send(List> list) {
for(int i = 0; i < list.size(); i++){
ProducerRecord record = list.get(i);
producer.send(record);
}
System.out.println("batch send to kafka successfully! num: " + list.size());
return;
}
public void shutdown() {
producer.close();
}
public static void main(String[] args) throws InterruptedException {
ProducerUtil kafkaProducer = new ProducerUtil();
String topic = "test_topic";
int sendTimes = 1000;
long time0 = System.currentTimeMillis();
String msg = "";
List> list = new ArrayList>();
for(int i=1;i<=sendTimes;i++){
msg = "["+i+"]test message";
ProducerRecord data = new ProducerRecord(topic, msg);
kafkaProducer.send(data);
}
long cost0 = System.currentTimeMillis()-time0;// 发送耗时并不是那么精确,因为LINGER_MS_CONFIG
System.out.println("发送["+sendTimes+"]条,耗时:"+cost0+"ms.");
}
}
对以上生产者实例有几点需要说明:
1.生产者发送类为什么使用单例?
:这个在官方文档中可以找到“The producer is thread safe and sharing a single producer instance across threads will generally be faster than having multiple instances.” 翻译过来就是“生产者是线程安全的,跨线程共享单个生成器实例通常比拥有多个实例更快”。
2.有些项目需要计算发送数据的耗时,但是在上面实例中的计算方法不甚合适。
:由于LINGER_MS_CONFIG参数的设置,虽然我们调用了send方法,但只是把数据放入了缓冲区,至于有没有发送到对应的分区,还要参考LINGER_MS_CONFIG参数的设置。另外,就算LINGER_MS_CONFIG有设置,这个设置参数也不一定会不折不扣的执行,因为“Note that records that arrive close together in time will generally batch together even with linger.ms=0
so under heavy load batching will occur regardless of the linger configuration”,就是说,当负荷比较大的时候,生产者会强制批量发送。话说回来,怎么样才能精确知道发送数据的耗时呢?笔者目前也不知道^_^.
3.上面实例的版本
:完整jar包名称是 kafka-clients-0.11.0.1.jar(在这里提一下,网上可以见到很多的这种实例但是很少有人把自己代码依赖的jar包详细版本说明的,这一点很不好,因为不同版本之间是有差异的,即使是细微的差异也可能导致运行报错,可能会把初学者卡半天,浪费大家时间!)