kafka详解(2):Kafka API实战

1、环境准备

(1)创建一个java工程,并将kafka安装包libs下的jar包拷贝到工程的lib目录下
(2)启动zk和kafka集群,在kafka集群中打开一个消费者
bin/kafka-console-consumer.sh --zookeeper hadoop03:2181 --topic testKafka

2、Kafka生产者JavaAPI

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

3、Kafka消费者JavaAPI

在控制台创建发送者
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、拦截器(interceptor)

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();

你可能感兴趣的:(kafka)