kafka学习笔记四Consumer学习

1.Consumer and Consumer Group  消费者与消费者分组

group.id  分组属性

client.id  consumer的id

2.Kafka Consumer programming  编程coding

package com.hanwan.kafka.demo2;


import org.apache.kafka.clients.consumer.Consumer;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.Collections;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName SimpleConsumer
 * @Description Consumer config demo
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/17 16:24
 * @Version 1.0
 **/
public class SimpleConsumer {

    private final static Logger LOGGER = LoggerFactory.getLogger(SimpleConsumer.class);

    public static void main(String[] args) {
        /*
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(loadProps());
        consumer.subscribe(Collections.singleton("test_c"));
        //表示永久循环
        for (;;) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            records.forEach(record ->{
                LOGGER.info("-----------------------------------------------------------------");
                LOGGER.info("offset {}",record.offset());
                LOGGER.info("value {}", record.value());
                LOGGER.info("partition {}", record.partition());
                LOGGER.info("key {}",record.key());
                LOGGER.info("-----------------------------------------------------------------");
            });
        }*/

        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(loadProps2());
        consumer.subscribe(Collections.singleton("test_c"));
        final AtomicInteger counter = new AtomicInteger();
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            records.forEach(record ->{
                LOGGER.info("--------------------------------------------------------");
                LOGGER.info("offset {}", record.offset());
                LOGGER.info("value {}", record.value());
                LOGGER.info("key {}", record.key());
                LOGGER.info("partition {}", record.partition());
                LOGGER.info("--------------------------------------------------------");
                int cnt = counter.getAndIncrement();
                if (cnt >= 3) {
                    Runtime.getRuntime().halt(-1);
                }
            });
        }
    }

    private static Properties loadProps(){
        final Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("group.id", "test_group3");
        prop.put("client.id", "demo-consumer-client");
        return prop;
    }

    private static Properties loadProps2(){
        final Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("group.id","test_group4");
        prop.put("client.id", "demo-consumer-client");
        prop.put("auto.offset.reset", "earliest");
        prop.put("enable.auto.commit", "true"); //默认为true自动提交
        prop.put("auto.commit.interval.ms", "10000"); //设置默认自动提交时间 ,默认值为5000ms
        return prop;
    }
}
package com.hanwan.kafka.demo2;

import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @ClassName ConsumerSyncCommit
 * @Description Consumer 同步commit
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/20 10:07
 * @Version 1.0
 **/
public class ConsumerSyncCommit {

    private final static Logger LOGGER = LoggerFactory.getLogger(ConsumerSyncCommit.class);

    public static void main(String[] args) {
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(loadProps());
        consumer.subscribe(Collections.singleton("test12"));
        final AtomicInteger count = new AtomicInteger(0);
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            records.forEach(record ->{
                LOGGER.info("key {}", record.key());
                LOGGER.info("partition {}", record.partition());
                LOGGER.info("offset {}", record.offset());
                LOGGER.info("value {}", record.value());
//                if (count.incrementAndGet() == 100) {
//                    consumer.commitSync();
//                    count.set(0);
//                }
            });
            /*
            * can retry
            * block
            * */
            consumer.commitSync();
        }
    }

    private static Properties loadProps(){
        final Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("group.id", "test_group1");
        prop.put("client.id", "demo-consumer-client");
        prop.put("auto.offset.reset", "earliest");
        prop.put("enable.auto.commit", "false");
        return prop;
    }
}
package com.hanwan.kafka.demo2;

import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.Properties;

/**
 * @ClassName ConsumerAsyncCommit
 * @Description Consumer 异步commit
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/20 13:28
 * @Version 1.0
 **/
public class ConsumerAsyncCommit {

    private final static Logger LOGGER = LoggerFactory.getLogger(ConsumerAsyncCommit.class);

    public static void main(String[] args) {
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(loadProp());
        consumer.subscribe(Collections.singleton("test12"));
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            records.forEach(record ->{
                LOGGER.info("key {}", record.key());
                LOGGER.info("partition {}", record.partition());
                LOGGER.info("offset {}", record.offset());
                LOGGER.info("value {}", record.value());
            });
            /*
            * can not by retry
            * non-block
            * */
            consumer.commitAsync((map, e) -> {
                if (e != null) {
                    e.printStackTrace();
                } else {
                    System.out.println(map);
                }
            });
        }
    }

    private static Properties loadProp(){
        final  Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("group.id", "test_group1");
        prop.put("client.id", "demo-consumer-client");
        prop.put("auto.offset.reset", "earliest");
        prop.put("enable.auto.commit", "false");
        return prop;
    }

}

4.Consumer configuration in deep  Consumer 的核心配置

·bootstrap.servers

在启动consumer时配置的broker地址的。不需要将cluster中所有的broker都配置上,因为启动后会自动的发现cluster所有的broker。

    它配置的格式是:host1:port1;host2:port2…

·key.descrializer、value.descrializer

Message record 的key, value的反序列化类。

·group.id

用于表示该consumer想要加入到哪个group中。默认值是 “”。

·heartbeat.interval.ms

心跳间隔。心跳是在consumer与coordinator之间进行的。心跳是确定consumer存活,加入或者退出group的有效手段。

    这个值必须设置的小于session.timeout.ms,因为:

当Consumer由于某种原因不能发Heartbeat到coordinator时,并且时间超过session.timeout.ms时,就会认为该consumer已退出,它所订阅的partition会分配到同一group 内的其它的consumer上。

    通常设置的值要低于session.timeout.ms的1/3。

    默认值是:3000 (3s)

·session.timeout.ms

Consumer session 过期时间。这个值必须设置在broker configuration中的group.min.session.timeout.ms 与 group.max.session.timeout.ms之间。

其默认值是:10000 (10 s)

·enable.auto.commit

Consumer 在commit offset时有两种模式:自动提交,手动提交。手动提交在前面已经说过。自动提交:是Kafka Consumer会在后台周期性的去commit。

默认值是true。

·auto.commit.interval.ms

    自动提交间隔。范围:[0,Integer.MAX],默认值是 5000 (5 s)

·auto.offset.reset

    这个配置项,是告诉Kafka Broker在发现kafka在没有初始offset,或者当前的offset是一个不存在的值(如果一个record被删除,就肯定不存在了)时,该如何处理。它有4种处理方式:

1) earliest:自动重置到最早的offset。

2) latest:看上去重置到最晚的offset。

3) none:如果边更早的offset也没有的话,就抛出异常给consumer,告诉consumer在整个consumer group中都没有发现有这样的offset。

4) 如果不是上述3种,只抛出异常给consumer。

默认值是latest。

·connections.max.idle.ms

连接空闲超时时间。因为consumer只与broker有连接(coordinator也是一个broker),所以这个配置的是consumer到broker之间的。

默认值是:540000 (9 min)

·fetch.max.wait.ms

Fetch请求发给broker后,在broker中可能会被阻塞的(当topic中records的总size小于fetch.min.bytes时),此时这个fetch请求耗时就会比较长。这个配置就是来配置consumer最多等待response多久。

·fetch.min.bytes

当consumer向一个broker发起fetch请求时,broker返回的records的大小最小值。如果broker中数据量不够的话会wait,直到数据大小满足这个条件。

取值范围是:[0, Integer.Max],默认值是1。

默认值设置为1的目的是:使得consumer的请求能够尽快的返回。

·fetch.max.bytes

一次fetch请求,从一个broker中取得的records最大大小。如果在从topic中第一个非空的partition取消息时,如果取到的第一个record的大小就超过这个配置时,仍然会读取这个record,也就是说在这片情况下,只会返回这一条record。

    broker、topic都会对producer发给它的message size做限制。所以在配置这值时,可以参考broker的message.max.bytes 和 topic的max.message.bytes的配置。

取值范围是:[0, Integer.Max],默认值是:52428800 (5 MB)

·max.partition.fetch.bytes

一次fetch请求,从一个partition中取得的records最大大小。如果在从topic中第一个非空的partition取消息时,如果取到的第一个record的大小就超过这个配置时,仍然会读取这个record,也就是说在这片情况下,只会返回这一条record。

    broker、topic都会对producer发给它的message size做限制。所以在配置这值时,可以参考broker的message.max.bytes 和 topic的max.message.bytes的配置。

·max.poll.interval.ms

前面说过要求程序中不间断的调用poll()。如果长时间没有调用poll,且间隔超过这个值时,就会认为这个consumer失败了。

·max.poll.records

    Consumer每次调用poll()时取到的records的最大数。

·receive.buffer.byte

Consumer receiver buffer (SO_RCVBUF)的大小。这个值在创建Socket连接时会用到。

取值范围是:[-1, Integer.MAX]。默认值是:65536 (64 KB)

如果值设置为-1,则会使用操作系统默认的值。

·request.timeout.ms

请求发起后,并不一定会很快接收到响应信息。这个配置就是来配置请求超时时间的。默认值是:305000 (305 s)

·client.id

Consumer进程的标识。如果设置一个人为可读的值,跟踪问题会比较方便。

·interceptor.classes

    用户自定义interceptor。

·metadata.max.age.ms

Metadata数据的刷新间隔。即便没有任何的partition订阅关系变更也行执行。

范围是:[0, Integer.MAX],默认值是:300000 (5 min)

4.Commit and offset  in deep Consumer的commit数据的方式

package com.hanwan.kafka.demo2;

import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.apache.kafka.clients.consumer.OffsetAndMetadata;
import org.apache.kafka.common.TopicPartition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @ClassName CommitSpecifiedOffset
 * @Description 指定partition的offset Commit
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/20 15:29
 * @Version 1.0
 **/
public class CommitSpecifiedOffset {

    private final static Logger LOGGER = LoggerFactory.getLogger(CommitSpecifiedOffset.class);

    public static void main(String[] args) {
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(loadProp());
        consumer.subscribe(Collections.singletonList("test12"));
        Map<TopicPartition, OffsetAndMetadata> offset = new HashMap<>();
        TopicPartition tp = new TopicPartition("test12", 1);
        OffsetAndMetadata om = new OffsetAndMetadata(35, "no meta data");
        offset.put(tp, om);
        try {
            while (true) {
                ConsumerRecords<String, String> records = consumer.poll(100);
                records.forEach(record -> {
                    LOGGER.info("partition {}, offset {}", record.partition(), record.offset());
                });
//                consumer.commitAsync();
                consumer.commitSync(offset);
            }
        } finally {
//            consumer.commitSync(offset);
        }
    }

    private static Properties loadProp(){
        final Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("group.id", "group_test11");
        prop.put("client.id", "demo-consumer-client");
        prop.put("auto.offset.reset", "earliest");
        prop.put("enable.auto.commit", "false");
        return prop;
    }
}
package com.hanwan.kafka.demo2;

import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.Properties;

/**
 * @ClassName CommitOffsetBothAsyncSync
 * @Description 同步异步结合的方式commit,推荐使用这种方式
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/20 14:30
 * @Version 1.0
 **/
public class CommitOffsetBothAsyncSync {

    private static Logger LOGGER = LoggerFactory.getLogger(CommitOffsetBothAsyncSync.class);

    public static void main(String[] args) {
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(loadProp());
        consumer.subscribe(Collections.singleton("test12"));
        try {

            while (true) {
                ConsumerRecords<String, String> records = consumer.poll(100);
                records.forEach(record -> {
                    LOGGER.info("key {}", record.key());
                    LOGGER.info("value {}", record.value());
                    LOGGER.info("partition {}", record.partition());
                    LOGGER.info("offset {}", record.offset());
                });
                //异步提交
                consumer.commitAsync();
            }
        } finally {
            //同步提交
            consumer.commitSync();
        }
    }

    private static Properties loadProp(){
        final Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("group.id", "group_test3");
        prop.put("client.id", "demo-consumer-client");
        prop.put("auto.offset.reset", "earliest");
        prop.put("enable.auto.commit", "false");
        return prop;
    }
}

5.Consumer programming in deep 深入分析Consumer的代码

6.Serializers & deserializers  序列化与反序列化

package com.hanwan.kafka.demo2.internal;

/**
 * @ClassName User
 * @Description TODO
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/20 17:08
 * @Version 1.0
 **/
public class User {

    private int id;
    private String name;
    private String address;

    public User(int id, String name, String address) {
        this.id = id;
        this.name = name;
        this.address = address;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getAddress() {
        return address;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}
package com.hanwan.kafka.demo2.internal;

import org.apache.kafka.common.serialization.Serializer;

import java.nio.ByteBuffer;
import java.util.Map;

/**
 * @ClassName UserSerializer
 * @Description TODO
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/20 17:33
 * @Version 1.0
 **/
public class UserSerializer implements Serializer<User> {


    @Override
    public void configure(Map<String, ?> map, boolean b) {
        //do nothing
    }

    @Override
    public byte[] serialize(String topic, User data) {
        if (data == null)
            return null;
        int id = data.getId();
        String name = data.getName();
        String address = data.getAddress();
        byte[] nameBytes;
        if (name != null)
            nameBytes = name.getBytes();
        else
            nameBytes = new byte[0];

        byte[] addressBytes;
        if (address != null)
            addressBytes = address.getBytes();
        else
            addressBytes = new byte[0];
        ByteBuffer buffer = ByteBuffer.allocate(4 + 4 + nameBytes.length + 4 + addressBytes.length);
        buffer.putInt(id);
        buffer.putInt(nameBytes.length);
        buffer.put(nameBytes);
        buffer.putInt(addressBytes.length);
        buffer.put(addressBytes);
        return buffer.array();
    }

    @Override
    public void close() {

    }
}
package com.hanwan.kafka.demo2.internal;

import org.apache.kafka.common.errors.SerializationException;
import org.apache.kafka.common.serialization.Deserializer;

import java.nio.ByteBuffer;
import java.util.Map;

/**
 * @ClassName UserDeserializer
 * @Description TODO
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/20 17:59
 * @Version 1.0
 **/
public class UserDeserializer implements Deserializer<User> {
    @Override
    public void configure(Map<String, ?> map, boolean b) {

    }

    @Override
    public User deserialize(String topic, byte[] data) {
        if (data == null)
            return null;
        if (data.length < 12)
            throw new SerializationException("The User data bytes length should not be less than 12.");
        ByteBuffer buffer = ByteBuffer.wrap(data);
        int id = buffer.getInt();
        int nameLength = buffer.getInt();
        byte[] nameBytes = new byte[nameLength];
        buffer.get(nameBytes);
        String name = new String(nameBytes);

        int addressLength = buffer.getInt();
        byte[] addressBytes = new byte[addressLength];
        buffer.get(addressBytes);
        String address = new String(addressBytes);
        return new User(id, name, address);
    }

    @Override
    public void close() {

    }
}
package com.hanwan.kafka.demo2;

import com.hanwan.kafka.demo2.internal.User;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.IntStream;

/**
 * @ClassName CustomerSerDeseSender
 * @Description 序列化 与反序列化producer方法
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/21 9:11
 * @Version 1.0
 **/
public class CustomerSerDeseSender {

    private final static Logger LOGGER = LoggerFactory.getLogger(CustomerSerDeseSender.class);

    public static void main(String[] args) {
        KafkaProducer<String, User> producer = new KafkaProducer<>(initProp());
        IntStream.range(1, 10).forEach(i ->{
            ProducerRecord<String, User> record = new ProducerRecord<>("test13", String.valueOf(i),new User(i, "name-"+i,"address-"+i));
            Future<RecordMetadata> future = producer.send(record);
            try {
                RecordMetadata recordMetadata = future.get();
                LOGGER.info("this message is send done the key is {}, offset {}", i, recordMetadata.offset());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        });
        producer.flush();
        producer.close();
    }

    private static Properties initProp(){
        final Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        prop.put("value.serializer", "com.hanwan.kafka.demo2.internal.UserSerializer");
        prop.put("acks", "all");
        return prop;
    }
}
package com.hanwan.kafka.demo2;

import com.hanwan.kafka.demo2.internal.User;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.Properties;

/**
 * @ClassName CustomerSerializerAndDeserializer
 * @Description consumer 的序列化与反序列化
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/20 18:18
 * @Version 1.0
 **/
public class CustomerSerializerAndDeserializer {

    private final static Logger LOGGER = LoggerFactory.getLogger(CustomerSerializerAndDeserializer.class);

    public static void main(String[] args) {
        KafkaConsumer<String, User> consumer = new KafkaConsumer<>(loadProp());
        consumer.subscribe(Collections.singletonList("test13"));
        while (true) {
            ConsumerRecords<String, User> records = consumer.poll(100);
            records.forEach(record ->{
                LOGGER.info("key {} value {}", record.key(), record.value());
            });
        }
    }

    private static Properties loadProp(){
        final Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "com.hanwan.kafka.demo2.internal.UserDeserializer");
        prop.put("group.id", "group_test15");
        prop.put("client.id", "demo-consumer-client");
        prop.put("auto.offset.reset", "earliest");
        prop.put("enable.auto.commit", "false");
        return prop;
    }

}

7.Consumer and Producer Interceptor生产者消费者拦截器

package com.hanwan.kafka.demo2;

import org.apache.kafka.clients.producer.ProducerInterceptor;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;

import java.util.Map;

/**
 * @ClassName MyProducerInterceptor
 * @Description 生产者拦截器重定义
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/21 10:30
 * @Version 1.0
 **/
public class MyProducerInterceptor implements ProducerInterceptor<String, String> {
    @Override
    public ProducerRecord<String, String> onSend(ProducerRecord<String, String> producerRecord) {
        return new ProducerRecord<>(producerRecord.topic(), producerRecord.partition(),
                producerRecord.timestamp(), producerRecord.key(),
                producerRecord.value().toUpperCase(), producerRecord.headers());
    }

    @Override
    public void onAcknowledgement(RecordMetadata recordMetadata, Exception e) {

    }

    @Override
    public void close() {

    }

    @Override
    public void configure(Map<String, ?> map) {

    }
}
package com.hanwan.kafka.demo2;

import org.apache.kafka.clients.consumer.ConsumerInterceptor;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.OffsetAndMetadata;
import org.apache.kafka.common.TopicPartition;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * @ClassName MyConsumerInterceptor
 * @Description Consumer拦截器demo
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/21 11:58
 * @Version 1.0
 **/
public class MyConsumerInterceptor implements ConsumerInterceptor<String, String> {
    @Override
    public ConsumerRecords<String, String> onConsume(ConsumerRecords<String, String> consumerRecords) {
        Map<TopicPartition, List<ConsumerRecord<String, String>>> results = new HashMap<>();
        Set<TopicPartition> partitions =  consumerRecords.partitions();
        partitions.forEach(p ->{
            List<ConsumerRecord<String, String>> result = consumerRecords.records(p)
                                        .stream().filter(record -> record.value().equals("HELLO8"))
                                        .collect(toList());
            results.put(p, result);
        });
        return new ConsumerRecords<>(results);
    }

    @Override
    public void onCommit(Map<TopicPartition, OffsetAndMetadata> offsets) {
        System.out.println("-----------begin--------------");
        System.out.println(offsets);
        System.out.println("-----------end--------------");
    }

    @Override
    public void close() {

    }

    @Override
    public void configure(Map<String, ?> map) {

    }
}
package com.hanwan.kafka.demo2;

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.clients.producer.RecordMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.IntStream;

/**
 * @ClassName SyncSenderWithInterceptor
 * @Description 拦截器producer测试类
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/21 10:44
 * @Version 1.0
 **/
public class SyncSenderWithInterceptor {

    private final static Logger LOGGER = LoggerFactory.getLogger(SyncSenderWithInterceptor.class);

    public static void main(String[] args) {
        KafkaProducer<String, String> producer = new KafkaProducer<>(initProp());
        IntStream.range(0, 10).forEach(i ->{
            ProducerRecord<String, String> record = new ProducerRecord<>("test14", String.valueOf(i),"hello"+i);
            Future<RecordMetadata> future = producer.send(record);
            try {
                RecordMetadata recordMetadata = future.get();
                LOGGER.info("this message is send done and the key is {}, offset {}", i, recordMetadata.offset());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        });
        producer.flush();
        producer.close();
    }

    private static Properties initProp(){
        final Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        prop.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        prop.put("acks", "all");
        prop.put(ProducerConfig.INTERCEPTOR_CLASSES_CONFIG, "com.hanwan.kafka.demo2.MyProducerInterceptor");
        return prop;
    }
}
package com.hanwan.kafka.demo2;

import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collections;
import java.util.Properties;

/**
 * @ClassName SimpleConsumerWithInterceptor
 * @Description Consumer拦截器demo测试
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/21 14:19
 * @Version 1.0
 **/
public class SimpleConsumerWithInterceptor {

    private final static Logger LOGGER = LoggerFactory.getLogger(SimpleConsumerWithInterceptor.class);

    public static void main(String[] args) {
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(loadProp());
        consumer.subscribe(Collections.singletonList("test14"));
        while (true) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            records.forEach(record ->{
                LOGGER.info("partition {}, value {}, offset {}", record.partition(), record.value(), record.offset());
            });
        }
    }

    private static Properties loadProp(){
        final Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("group.id", "g5");
        prop.put("client.id", "demo-interceptor-client");
        prop.put("auto.offset.reset", "earliest");
        prop.put("auto.commit.interval.ms", "10000");
        prop.put(ConsumerConfig.INTERCEPTOR_CLASSES_CONFIG, "com.hanwan.kafka.demo2.MyConsumerInterceptor");
        return prop;
    }
}

8.Consumer and Rebalance  消费者的平衡

package com.hanwan.kafka.demo2;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.clients.producer.RecordMetadata;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.IntStream;

/**
 * @ClassName RebalanceSender
 * @Description Rebalance Producer
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/21 15:33
 * @Version 1.0
 **/
public class RebalanceSender {

    private final static Logger LOGGER = LoggerFactory.getLogger(RebalanceSender.class);

    public static void main(String[] args) {
        KafkaProducer<String, String> producer = new KafkaProducer<>(initProp());
        IntStream.range(20, 30).forEach(i ->{
            ProducerRecord<String, String> record = new ProducerRecord<>("test16",String.valueOf(i), "hello"+i);
            Future<RecordMetadata> future = producer.send(record);
            try {
                RecordMetadata recordMetadata = future.get();
                LOGGER.info("this message is send done and the key is{}, offset {}", i, recordMetadata.offset());
            } catch (InterruptedException | ExecutionException e) {
                e.printStackTrace();
            }
        });
        producer.flush();
        producer.close();
    }

    private static Properties initProp(){
        final Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        prop.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        prop.put("acks", "all");
        return prop;
    }
}
package com.hanwan.kafka.demo2;

import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.TopicPartition;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Collection;
import java.util.Collections;
import java.util.Properties;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName RebalanceConsumer
 * @Description Rebalance  Consumer  demo
 * @Copyright: Copyright (c) 2018</p>
 * @Company: www.lowan.com</ p>
 * @Author hanwan
 * @Date 2018/8/21 15:12
 * @Version 1.0
 **/
public class RebalanceConsumer {

    private final static Logger LOGGER = LoggerFactory.getLogger(RebalanceConsumer.class);

    public static void main(String[] args) {
        KafkaConsumer<String, String> consumer = new KafkaConsumer<>(loadProp());
        consumer.subscribe(Collections.singletonList("test16"));
        for (; ; ) {
            ConsumerRecords<String, String> records = consumer.poll(100);
            records.forEach(record ->{
                LOGGER.info("partition {}, key {}, value {}, offset {}", record.partition(), record.key(), record.value(), record.offset());
                try {
                    TimeUnit.SECONDS.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
            consumer.commitSync();
        }
    }

    private static Properties loadProp(){
        final Properties prop = new Properties();
        prop.put("bootstrap.servers", "120.55.125.58:9092,120.26.198.248:9092,121.40.200.37:9092");
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("group.id", "group-rebalance");
        prop.put("client.id", "demo-rebalance-client3");
        prop.put("auto.offset.reset", "earliest");
        prop.put(ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG, "false");
//        prop.put("auto.commit.interval.ms", "10000");
        return prop;
    }

    private static class MyConsumerBanalanceListener implements ConsumerRebalanceListener {

        private final KafkaConsumer<String, String> consumer;

        private MyConsumerBanalanceListener(KafkaConsumer<String, String> consumer) {
            this.consumer = consumer;
        }

        @Override
        public void onPartitionsRevoked(Collection<TopicPartition> partitions) {
            for (TopicPartition partition : partitions) {
                long nextOffset = consumer.position(partition);
                //nextOffset partition save
            }
            LOGGER.info("onPartitionsRevoked=> {}", partitions);
        }

        @Override
        public void onPartitionsAssigned(Collection<TopicPartition> partitions) {
            for (TopicPartition partition : partitions) {
                consumer.seek(partition, 0);
            }
            LOGGER.info("onPartitionsAssigned=> {}", partitions);
        }
    }
}

再均衡监听器

      在为消费者分配新的partition或者移除旧的partition时,可以通过消费者API执行一些应用程序代码,在使用subscribe()方法时传入一个ConsumerRebalanceListener实例。

     ConsumerRebalanceListener需要实现的两个方法:

    1) public void onPartitionRevoked(Collection<TopicPartition> partitions)方法会在再均衡开始之前和消费者停止读取消息之后被调用。如果在这里提交偏移量,下一个接管partition的消费者就知道该从哪里开始读取了。

    2) public void onPartitionAssigned(Collection<TopicPartition> partitions)方法会在重新分配partition之后和消费者开始读取消息之前被调用。

猜你喜欢

转载自blog.csdn.net/hwhanwan/article/details/81776753
今日推荐