(1)创建一个java工程,并将kafka安装包libs下的jar包拷贝到工程的lib目录下
(2)启动zk和kafka集群,在kafka集群中打开一个消费者
bin/kafka-console-consumer.sh --zookeeper hadoop03:2181 --topic testKafka
2.1 创建生产者(过时的API)
Properties properties = new Properties();
properties.put("metadata.broker.list","hadoop05:9092");
properties.put("request.required.acks","1");
properties.put("serializer.class","kafka.serializer.StringgEncoder");
Producer producer = new Producer(new
ProducerConfig(properties));
KeyedMessage message = new KeyedMessage("testKafka","helloworld");
producer.send(message);
2.2、创建生产者(新API)
Properties pros = new Properties();
//Kafka服务端的主机名和端口号
pros.put("bootstrap.servers","hadoop05:9092");
//等待所有副本节点的应答
pros.put("acks","all");
//消息发送最大尝试次数
pros.put("retries",0);
//一批消息处理大小
pros.put("batch.size",16384);
//请求延时
pros.put("linger.ms",1);
//发送给缓存区内存大小
pros.put("buffer.memory",33554432);
//key序列化
pros.put("key.serializer","org.apach.kafka.common.serialization.StringSerializer");
//value序列化
pros.put("value.serializer","org.apach.kafka.common.serialization.StringSerializer");
KafkaProducer producer = new KafkaProducer(pros);
for (int i = 0; i < 50; i++) {
producer.send(new ProducerRecord("testKafka",Integer.toString(i),"hello word-" + i));
}
producer.close();
2.3、创建生产者带回调函数(新API)
Properties properties = new Properties();
//Kafka服务端主机名和端口号
properties.put("bootstrap.servers","hadoop05:9092");
//等待所有副本节点的应答
properties.put("acks","all");
//消息发送最大尝试次数
properties.put("retries",0);
//一批消息处理大小
properties.put("batch.size",16384);
//增加服务端请求延时
properties.put("linger.ms",1);
//发送缓存区内存大小
properties.put("buffer.memory",3355442);
//key序列化
properties.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
// value 序列化
properties.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
KafkaProducer kafkaProducer = new KafkaProducer<>(properties);
for (int i = 0; i < 50; i++) {
kafkaProducer.send(new ProducerRecord("testKafka", "hello" + i), new Callback() {
@Override
public void onCompletion(RecordMetadata recordMetadata, Exception e) {
if (recordMetadata != null){
System.out.println(recordMetadata.partition() + "--"+recordMetadata.offset());
}
}
});
}
2.4、自定义分区生产者
需求:将所有数据存储到topic的第0号分区上
(1)定义一个类实现Partitioner接口,重写里面的方法(过时API)
import kafka.producer.Partitioner;
@Override
public int partition(Object key, int numPartitions) {
//控制分区
return 0;
}
public CustomPartitioner(){
super();
}
(2)自定义分区,新API
import org.apache.kafka.clients.producer.Partitioner;
@Override
public int partition(String s, Object o, byte[] bytes, Object o1, byte[] bytes1, Cluster cluster) {
//控制分区
return 0;
}
@Override
public void close() {
}
@Override
public void configure(Map map) {
}
(3)在代码中调用
Properties props = new Properties();
// Kafka 服务端的主机名和端口号
props.put("bootstrap.servers", "hadoop103:9092");
// 等待所有副本节点的应答
props.put("acks", "all");
// 消息发送最大尝试次数
props.put("retries", 0);
// 一批消息处理大小
props.put("batch.size", 16384);
// 增加服务端请求延时
props.put("linger.ms", 1);
// 发送缓存区内存大小
props.put("buffer.memory", 33554432);
// key 序列化
props.put("key.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
// value 序列化
props.put("value.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
//自定义分区
props.put("partitioner.class","kafka.CustomPartitioner");
Producer producer = new KafkaProducer<>(props);
producer.send(new ProducerRecord("testKafka", "1", "hello kafka"));
producer.close();
(4)测试
在hadoop03上监控kafka/logs/目录下testKafka话题下3个分区的动态变化
tail -f firt-0/000000000000000.log
在控制台创建发送者
bin/kafaka-console-producer.sh --broker-list hadoop01:9092 --topic testKafka
>hello world
3.1、创建消费者(过时API)
Properties properties = new Properties();
properties.put("zookeeper.connect","hadoop05:2181");
properties.put("group.id","g1");
properties.put("zookeeper.session.timeout.ms","500");
properties.put("zookeeper.sync.time.ms","250");
properties.put("auto.commit.interval.ms","1000");
//创建消费者连接器
ConsumerConnector connector = Consumer.createJavaConsumerConnector(new ConsumerConfig(properties));
HashMap topicCount = new HashMap<>();
topicCount.put("testKafka",1);
Map>> consumerMap = connector.createMessageStreams(topicCount);
KafkaStream stream = consumerMap.get("testKafka").get(0);
ConsumerIterator it = stream.iterator();
while (it.hasNext()){
System.out.println(new String(it.next().message()));
}
3.2、官方提供案例(自动维护消费情况,新API)
Properties props = new Properties();
// 定义 kakfa 服务的地址,不需要将所有 broker 指定上
props.put("bootstrap.servers", "hadoop102:9092");
// 制定 consumer group
props.put("group.id", "test");
// 是否自动确认 offset
props.put("enable.auto.commit", "true");
// 自动确认 offset 的时间间隔
props.put("auto.commit.interval.ms", "1000");
// key 的序列化类
props.put("key.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
// value 的序列化类
props.put("value.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
// 定义 consumer
KafkaConsumer consumer = new KafkaConsumer<>(props);
//消费订阅的topic,可同时订阅多个
consumer.subscribe(Arrays.asList("testKafka1","testKafka2"));
while (true){
//读取数据,超时时间为100ms
ConsumerRecords records = consumer.poll(100);
for (ConsumerRecord record: records) {
System.out.println("offset = %d, key = %s, value = %s%n", record.offset(),record.key(), record.value());
}
}
4.1、拦截器原理
producer拦截器主要用于实现clients端的定制化控制逻辑;
对于producer而言,interceptor使得用户在发送消息前以及producer回调逻辑前有机会对消息做一些定制化需求,比如修改消息等;
同时,producer允许用户指定多个拦截器按序作用于同一条消息,从而形成要给拦截器连;
Interceptor的实现接口是kafka.clients.producer.ProducerInterceptor,其定义的 方法包括:
(1)configure(configs)
获取配置信息和初始化数据时调用
(2)onSend(ProducerRecord):
该方法封装金KafkaProducer.send方法中,即它运行在用户主线程中。Producer确保在消息被序列化以及计算分区前调用该方法。用户可以在该方法中对消息做任何操作,但最好保证不要修改消息所属的topic和分区,否则会影响目标分区的计算。
(3)onAcknowledgement(RecordMetadata,Exception)
该方法在消息被应答或消息发送失败时调用,并且通常都是在producer回调逻辑触发之前。该方法运行在producer的IO线程中,因此不要在该方法中放入很重要的逻辑,否则会拖慢producer的消息发送效率
(4)close
关闭拦截器,主要执行一些资源清理工作。
4.2、拦截器案例
1、需求:实现一个简单的双拦截器组成的拦截链,第一个interceptor会在消息发送前将时间戳信息加到信息value的最前不;第二个interceptor会在消息发送成功后更新成功发送消息数或失败发送消息数
2、案例操作
(1)时间拦截器
@Override
public ProducerRecord onSend(ProducerRecord producerRecord) {
//创建一个新的record,把时间戳写入消息体的最前部
return new ProducerRecord<>(producerRecord.topic(),producerRecord.partition(),producerRecord.timestamp(),producerRecord.key(),System.currentTimeMillis()+","+producerRecord.value().toString());
}
(2)统计拦截器
private int errorCounter = 0;
private int successCounter = 0;
@Override
public ProducerRecord onSend(ProducerRecord producerRecord) {
return producerRecord;
}
@Override
public void onAcknowledgement(RecordMetadata recordMetadata, Exception e) {
//统计成功和失败的次数
if (e == null){
successCounter ++;
}else {
errorCounter ++;
}
}
@Override
public void close() {
//保存结果
System.out.println("successful sent:" + successCounter);
System.out.println("Failed sent:" + errorCounter);
}
(3)程序运行主类
// 1 设置配置信息
Properties props = new Properties();
props.put("bootstrap.servers", "hadoop102:9092");
props.put("acks", "all");
props.put("retries", 0);
props.put("batch.size", 16384);
props.put("linger.ms", 1);
props.put("buffer.memory", 33554432);
props.put("key.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
props.put("value.serializer",
"org.apache.kafka.common.serialization.StringSerializer");
//2 构建拦截器链
List interceptors = new ArrayList<>();
interceptors.add("kafka.TimeInterceptor");
interceptors.add("kafka.CounterInterceptor");
props.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG,interceptors);
String topic = "testKafka";
Producer producer = new KafkaProducer(props);
//发送消息
for (int i = 0; i <10; i++) {
ProducerRecord record = new ProducerRecord(topic,"message" + 1);
producer.send(record);
}
//一定要关闭producer,这样才会调用interceptor的close方法
producer.close();