kafka_生产者API _Consumer

本文详细介绍了ApacheKafka消费者在处理数据时如何确保数据可靠性,包括自动提交offset的功能、不同offset重置策略以及手动提交offset(commitSync和commitAsync)的应用。特别关注了在故障恢复时如何从正确的位置继续消费。
摘要由CSDN通过智能技术生成

消费者API _Consumer

Consumer消费数据时的可靠性是很容易保证的,因为数据在Kafka中是持久化的,故不用担心数据丢失问题。

由于consumer在消费过程中可能会出现断电宕机等故障,consumer恢复后,需要从故障前的位置的继续消费,所以consumer需要实时记录自己消费到了哪个offset,以便故障恢复后继续消费。所以offset的维护是Consumer消费数据是必须考虑的问题。

1.自动提交offset

(1)编写代码:需要用到的类:

KafkaConsumer:需要创建一个消费对象,用来消费

ConsumerConfig:需要所需的配置参数

ConsumerRecord: 每条数据都要封装成一个ConsumerRecord对象

为为了使我们能够专注于自己的业务逻辑,Kafka提供了自动提交offset的功能。

自动提交offset的相关参数:

enable.auto.commit:是否开启自动提交offset功能

auto.commit.interval.ms:自动提交offset的时间间隔

java代码:

package com.itwise.kafka.consumer;

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 org.apache.kafka.clients.producer.KafkaProducer;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Properties;

public class MyConsumerDome {
    /**
     * 演示消费者
     */
    public static void main(String[] args) {
//        创建连接数
        Properties prop = new Properties();
//        连接用户
        prop.put("bootstrap.servers", "node2:9092");
//        创建组号,看是否为新
        prop.put("group.id", "java");
//        是否自动提交
        prop.put("enable.auto.commit", "true");
//        设置提交时间,1000要加引号!!!!
        prop.put("auto.commit.interval.ms", "1000");
//        连接
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
//        offset重设
//        最早的,开头,就是from-beginning
        prop.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"earliest");
//        最新的,也就是末尾
//        prop.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"latest");
//        默认
//        prop.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"none");

//        与kafka进行连接,将上面设置的参数添加进取
//        注意是消费者!!!!!
        KafkaConsumer<String, String> kafkaConsumer
                = new KafkaConsumer<String, String>(prop);
//        KafkaProducer<String, String> stringStringKafkaProducer = new KafkaProducer<String, String>(prop);
//        消费者订阅消息,定义集合储存主题
        ArrayList<String> topicList = new ArrayList<>();
        topicList.add("itwise"); //添加主题
//topiclist.add("hadoop11"); //没有topic,会创建topic,1分区1副本的topic
//        添加消费者消费的 主题
        kafkaConsumer.subscribe(topicList);
//        消费者循环取出数据
        while (true){
            ConsumerRecords<String, String> poll = kafkaConsumer.poll(Duration.ofSeconds(2));
//            强循环取出数据输出到控制台
            for (ConsumerRecord<String, String> ConsumerRecord : poll) {
                System.out.println(ConsumerRecord.topic()+"--"+
                        ConsumerRecord.partition()+"--"+
                        ConsumerRecord.offset()+"--"+
                        ConsumerRecord.key()+"--"+
                        ConsumerRecord.value());
            }
        }

//        一直等待接收,不需要关闭
//        kafkaConsumer.close();
    }
}

虚拟机建立生产者:producer 输入数据

[itwise@node2 ~]$ kafka-console-producer.sh --broker-list node2:9092 --topic itwise
>aaaa

1,最早的结果展示: 有旧原有的数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2.最末尾的数据: 不会产生原有的数据

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

3 none:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

2重置offset

auto.offset.rest = earliest | latest | none |

注意:

知识点: 一组消费者,每个消费者负责一个分区,itwise会自动的去记录维护offset,但是对于一个后开启的新组的消费者,则看不到该生产者生产的topic中以前的数据, 因为 offset默认的是latest,位置

在最后。需要观察的是:新组(组号要是新的),修改消费者代码中设置auto.offset.reset=earliest,然后启动消费者代码。观察是否将分区中以前的数据读取出来了。

手动提交offset

虽然自动提交offset十分简介便利,但由于其是基于时间提交的,开发人员难以把握offset提交的时机。因此Kafka还提供了手动提交offset的API。手动提交offset的方法有两种:分别是commitSync(同步提交)和commitAsync(异步提交)。两者的相同点是,都会将本次poll的一批数据最高的偏移量提交;不同点是,commitSync阻塞当前线程,

一直到提交成功,并且会自动失败重试(由不可控因素导致,也会出现提交失败);而commitAsync则没有失败重试机制,故有可能提交失败。

(1)同步提交offset

创建一个topic
kafka-topics.sh --create --topic my_Consumer --bootstrap-server node2:9092 --
partitions 2 --replication-factor 3
# 生产数据:
kafka-console-producer.sh --broker-list node2:9092 --topic my_Consumer
# 消费者
kafka-console-consumer.sh --bootstrap-server node2:9092 --topic my_Consumer

(2)java同步代码实现:

package com.itwise.kafka.consumer;

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.time.Duration;
import java.util.ArrayList;
import java.util.Properties;

public class MyConsumerDome_tonbu {
    /**
     * 演示消费者
     */
    public static void main(String[] args) {
//        创建连接数
        Properties prop = new Properties();
//        连接用户
        prop.put("bootstrap.servers", "node2:9092");
//        创建组号,看是否为新
        prop.put("group.id", "ConsumerDome");

//        关闭自动提交
        prop.put("enable.auto.commit", "false");

//        设置提交时间,1000要加引号!!!!
//        prop.put("auto.commit.interval.ms", "1000");
//        连接
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
//        offset重设
//        最早的,开头
        prop.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"earliest");
//        最新的,也就是末尾
//        prop.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"latest");
//        默认
//        prop.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"none");

//        与kafka进行连接,将上面设置的参数添加进取
//        注意是消费者!!!!!
        KafkaConsumer<String, String> kafkaConsumer
                = new KafkaConsumer<String, String>(prop);
//        KafkaProducer<String, String> stringStringKafkaProducer = new KafkaProducer<String, String>(prop);

//        消费者订阅消息,定义集合储存主题
        ArrayList<String> topicList = new ArrayList<>();
        topicList.add("my_Consumer"); //添加主题
//topiclist.add("my_Consumer"); //没有topic,会创建topic,1分区1副本的topic
//        添加消费者消费的 主题
        kafkaConsumer.subscribe(topicList);
//        消费者循环取出数据
        while (true){
            ConsumerRecords<String, String> poll = kafkaConsumer.poll(Duration.ofSeconds(2));
//            强循环取出数据输出到控制台
            for (ConsumerRecord<String, String> ConsumerRecord : poll) {
                System.out.println(ConsumerRecord.topic()+"--"+
                        ConsumerRecord.partition()+"--"+
                        ConsumerRecord.offset()+"--"+
                        ConsumerRecord.key()+"--"+
                        ConsumerRecord.value());
            }

            System.out.println("同步提交offset");
            kafkaConsumer.commitAsync();

        }

//        一直等待接收,不需要关闭
//        kafkaConsumer.close();
    }
}

同步: 拉取信息与提交文字同步,再提取下一个

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

异步代码的实现

package com.itwise.kafka.consumer;

import org.apache.kafka.clients.consumer.*;
import org.apache.kafka.common.TopicPartition;

import java.time.Duration;
import java.util.ArrayList;
import java.util.Map;
import java.util.Properties;

public class MyConsumerDome_yibu {
    /**
     * 演示消费者
     */
    public static void main(String[] args) {
//        创建连接数
        Properties prop = new Properties();
//        连接用户
        prop.put("bootstrap.servers", "node2:9092");
//        创建组号,看是否为新
        prop.put("group.id", "ConsumerDome");

//        关闭自动提交
        prop.put("enable.auto.commit", "false");

//        设置提交时间,1000要加引号!!!!
//        prop.put("auto.commit.interval.ms", "1000");
//        连接
        prop.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
        prop.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
//        offset重设
//        最早的,开头
        prop.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"earliest");
//        最新的,也就是末尾
//        prop.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"latest");
//        默认
//        prop.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG,"none");

//        与kafka进行连接,将上面设置的参数添加进取
//        注意是消费者!!!!!
        KafkaConsumer<String, String> kafkaConsumer
                = new KafkaConsumer<String, String>(prop);
//        KafkaProducer<String, String> stringStringKafkaProducer = new KafkaProducer<String, String>(prop);

//        消费者订阅消息,定义集合储存主题
        ArrayList<String> topicList = new ArrayList<>();
        topicList.add("my_Consumer"); //添加主题
//topiclist.add("my_Consumer"); //没有topic,会创建topic,1分区1副本的topic
//        添加消费者消费的 主题
        kafkaConsumer.subscribe(topicList);
//        消费者循环取出数据
        while (true){
            ConsumerRecords<String, String> poll = kafkaConsumer.poll(Duration.ofSeconds(2));
//            强循环取出数据输出到控制台
            for (ConsumerRecord<String, String> ConsumerRecord : poll) {
                System.out.println(ConsumerRecord.topic()+"--"+
                        ConsumerRecord.partition()+"--"+
                        ConsumerRecord.offset()+"--"+
                        ConsumerRecord.key()+"--"+
                        ConsumerRecord.value());
            }

         /*   System.out.println("同步提交offset");
            kafkaConsumer.commitAsync();*/

//            异步提交
            System.out.println("异步提交offset");
//            调用commitAsync静态方法,设置提交回调函数
            kafkaConsumer.commitAsync(new OffsetCommitCallback() {
                @Override
                public void onComplete(Map<TopicPartition, OffsetAndMetadata> map, Exception e) {
                    if (e == null) {
//                        有异常
                        System.out.println("异步提交成工");
                    }else {
//                        异步提交失败,返回失败原因
                        System.out.println(e.getMessage());
                    }
                    
                }
            });
            

        }

//        一直等待接收,不需要关闭
//        kafkaConsumer.close();
    }
}

异步:先拉数据,再提交文字

        }else {

// 异步提交失败,返回失败原因
System.out.println(e.getMessage());
}

            }
        });
        

    }

// 一直等待接收,不需要关闭
// kafkaConsumer.close();
}
}


异步:先拉数据,再提交文字

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-home.csdnimg.cn/images/20230724024159.png?origin_url=C%3A%5CUsers%5CAdministrator%5CAppData%5CRoaming%5CTypora%5Ctypora-user-images%5Cimage-20240314190908172.png&pos_id=img-ecL7IcwZ-1713315048031)
  • 22
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值