文章目录

  • 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。

kafka有哪些端口 kafka接口规范_big data

相关参数:

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>
  1. 不带回调函数的 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集群上启动一个代码中对应的消费者:

kafka有哪些端口 kafka接口规范_kafka_02

  1. 带回调函数的 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();
    }
}

控制台输出:

kafka有哪些端口 kafka接口规范_java_03

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

kafka有哪些端口 kafka接口规范_java_04

**重置消费者的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去设定的,本文中的部分示例用的是参数名的形式,两种都是可以的,推荐使用配置类去设置参数。