kafka系列9——第3章1——消费者

 🌈hello,你好鸭,我是Ethan,西安电子科技大学大三在读,很高兴你能来阅读。

✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!

🔥个人主页:Ethan Yankang
🔥推荐:史上最强八股文||一分钟看完我的几百篇博客

🔥温馨提示:划到文末发现专栏彩蛋   点击这里直接传送

🔥本篇概览:详细讲解了kafka系列9——第3章1——消费者。🌈⭕🔥


【计算机领域一切迷惑的源头都是基本概念的模糊,算法除外】


🔥   微服务全集

🔥   kafka全集

🔥   前一篇章


🌈引出

Apache的kafka是一个分布式的消息发布订阅中间件。具有高吞吐、可扩展和容错性等特点。主要用于处理大规模的流式数据

本博客从各个方面详细讲解了kafka的机制,并实际上手使用之,好好学完定会习得大功。(bushi,上一次面试就噶在kafka上了,好好对待之。)


tips 学完这一章你可以
深入学习 Kafka 数据消费大致流程
如何创建并使用 Kafka 消费者
Kafka 消费者常用配置

3.1 概念入门

3.1.1 消费者和消费组

Kafka 消费者是 消费组 的一部分, 当多个消费者形成一个消费组来消费主题时,每个消费者会收到不同分区的消息。
假设有一个T1 主题,该主题有 4 个分区;同时我们有一个消费组 G1 ,这个消费组只有一个消费者C1 。那么消费者 C1 将会收到这 4 个分区的消息,如下所示:

        Kafka一个很重要的特性就是,只需写入一次消息,可以支持任意多的应用读取这个消息。换句话说,每个应用都可以读到全量的消息。[意思就是消息支持重复读取]。为了使得每个应用都能读到全量消息,应用需要有不同的消费组。对于上面的例子,假如我们新增了一个新的消费组G2 ,而这个消费组有两个消费者,那么会是这样的:

【支持消息重读】

3.2 消息接收

3.2.1必要参数设置

KafkaConsumer 实例中参数众多,后续会深入讲解

public static Properties initConfig() {
    Properties props = new Properties();
    
    // 设置 key 的反序列化器。Kafka 从 broker 获取的消息是字节数组,因此需要将字节数组反序列化为 Java 对象。
    props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
    
    // 设置 value 的反序列化器。与 key 的反序列化器相同,将消息的 value 部分反序列化。
    props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
    
    // 设置 Kafka 集群的 broker 地址,用于连接 Kafka 集群。这个配置项非常重要,必须设置。
    props.put("bootstrap.servers", brokerList);
    
    // 设置消费者所属的消费组 ID。消费者必须属于某一个消费组,通过消费组管理消息的消费情况。
    props.put("group.id", groupId);
    
    // 设置消费者客户端 ID。用于标识消费者客户端的唯一性,便于 Kafka 集群追踪和管理。
    props.put("client.id", "consumer.client.id.demo");
    
    return props;
}

3.2.2 订阅主题和分区

        创建完消费者后我们便可以订阅主题了,只需要通过调用 subscribe() 方法即可,这个方法接收一个主题列表:
KafkaConsumer<String, String> consumer = new KafkaConsumer<>(props);
consumer.subscribe(Arrays.asList(topic));
        另外,我们也可以使用正则表达式来匹配多个主题,而且订阅之后如果又有匹配的新主题,那么这个消费组会立即对其进行消费。正则表达式在连接Kafka与其他系统时非常有用。比如订阅所有的测试主题:
consumer.subscribe(Pattern.compile("heima*"));
        指定订阅的分区:
// 指定订阅的分区
consumer.assign(Arrays.asList(new TopicPartition("topic0701", 0)));

3.2.3 反序列化

// 与KafkaProducer中设置保持一致
props.put("key.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");
props.put("value.deserializer",
"org.apache.kafka.common.serialization.StringDeserializer");

3.2.4 位移提交

         对于Kafka中的分区而言,它的每条消息都有唯一的offset,用来表示消息在分区中的位置。
当我们调用 poll() 时,该方法会返回我们没有消费的消息。当消息从 broker返回消费者时,broker并不跟踪这些消息是否被消费者接收到;Kafka让消费者自身来管理消费的位移,并向消费者提供更新位移的接口,这种更新位移方式称为提交(commit)。

重复消费

消息丢失

同步提交

见代码库: com.heima.kafka.chapter3.CheckOffsetAndCommit


自动提交

        这种方式让消费者来管理位移,应用本身不需要显式操作。当我们将enable.auto.commit 设置为 true 那么消费者会在poll 方法调用后每隔5秒(由auto.commit.interval.ms 指定)提交一次位移。和很多其他操作一样,自动提交也是由poll() 方法来驱动的;在调用 poll() 时,消费者判断是否到达提交时间,如 果是则提交上一次poll 返回的最大位移。
        需要注意到,这种方式可能会导致消息重复消费。假如,某个消费者poll 消息后,应用正在处理消息,在3 秒后 Kafka 进行了重平衡,那么由于没有更新位移导致重平衡后这部分消息重复消费。


异步提交

        手动提交有一个缺点,那就是当发起提交调用时应用会阻塞。当然我们可以减少手动提交的频率,但这个会增加消息重复的概率(和自动提交一样)。另外一个解决办法是,使用异步提交的API。

        但是异步提交也有个缺点,那就是如果服务器返回提交失败,异步提交不会进行重试。相比较起来,同 步提交会进行重试直到成功或者最后抛出异常给应用。异步提交没有实现重试是因为,如果同时存在多 个异步提交,进行重试可能会导致位移覆盖。举个例子,假如我们发起了一个异步提交commitA,此时的提交位移为2000 ,随后又发起了一个异步提交 commitB 且位移为 3000 commitA 提交失败但commitB提交成功,此时 commitA 进行重试并成功的话,会将实际上将已经提交的位移从 3000 回滚到2000,导致消息重复消费。

3.2.5 指定位移消费

到目前为止,我们知道消息的拉取是根据 poll() 方法中的逻辑来处理的,但是这个方法对于普通开发人员来说就是个黑盒处理,无法精确掌握其消费的起始位置。
seek() 方法正好提供了这个功能,让我们得以追踪以前的消费或者回溯消费。
指定从分区末尾开始消费
演示位移越界操作        
会通过 auto.offset.reset 参数的默认值将位置重置

3.2.6 再均衡监听器

        再均衡是指分区的所属从一个消费者转移到另外一个消费者的行为,它为消费组具备了高可用性和伸缩性提供了保障使得我们既方便又安全地删除消费组内的消费者或者往消费组内添加消费者。不过再均衡发生期间,消费者是无法拉取消息的。

3.2.5 消费者拦截器

之前章节讲了生产者拦截器,对应的消费者也有相应的拦截器概念,消费者拦截器主要是在消费到消息或者在提交消费位移时进行的一些定制化的操作。

3.2.6 消费者参数补充

fetch.min.bytes

这个参数允许消费者指定从 broker 读取消息时最小的数据量。当消费者从 broker 读取消息时,如果数据量小于这个阈值,broker 会等待直到有足够的数据,然后才返回给消费者。对于写入量不高的主题来说,这个参数可以减少broker 和消费者的压力,因为减少了往返的时间。而对于有大量消费者的主题来说,则可以明显减轻broker 压力。

fetch.max.wait.ms

上面的 fetch.min.bytes 参数指定了消费者读取的最小数据量,而这个参数则指定了消费者读取时最长等待时间,从而避免长时间阻塞。这个参数默认为500ms

max.partition.fetch.bytes

这个参数指定了每个分区返回的最多字节数,默认为 1M 。也就是说, KafkaConsumer.poll() 返回记录列表时,每个分区的记录字节数最多为1M 。如果一个主题有 20 个分区,同时有 5 个消费者,那么每个消费者需要4M 的空间来处理消息。实际情况中,我们需要设置更多的空间,这样当存在消费者宕机时,其他消费者可以承担更多的分区。

max.poll.records

这个参数控制一个 poll() 调用返回的记录数,这个可以用来控制应用在拉取循环中的处理数据量。



💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖

热门专栏推荐

🌈🌈计算机科学入门系列                     关注走一波💕💕

🌈🌈CSAPP深入理解计算机原理        关注走一波💕💕

🌈🌈微服务项目之黑马头条                 关注走一波💕💕

🌈🌈redis深度项目之黑马点评            关注走一波💕💕

🌈🌈JAVA面试八股文系列专栏           关注走一波💕💕

🌈🌈JAVA基础试题集精讲                  关注走一波💕💕   

🌈🌈代码随想录精讲200题                  关注走一波💕💕


总栏

🌈🌈JAVA基础要夯牢                         关注走一波💕💕  

🌈🌈​​​​​​JAVA后端技术栈                          关注走一波💕💕  

🌈🌈JAVA面试八股文​​​​​​                          关注走一波💕💕  

🌈🌈JAVA项目(含源码深度剖析)    关注走一波💕💕  

🌈🌈计算机四件套                               关注走一波💕💕  

🌈🌈数据结构与算法                           ​关注走一波💕💕  

🌈🌈必知必会工具集                           关注走一波💕💕

🌈🌈书籍网课笔记汇总                       关注走一波💕💕         



📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤收藏✅ 评论💬,大佬三连必回哦!thanks!!!
📚愿大家都能学有所得,功不唐捐!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值