kafka教程1:Consumer,消费者

本文详细介绍了KafkaConsumer的原理和使用,包括消费者位置、消费者组、订阅、失效检测等概念。KafkaConsumer是线程不安全的,用于从Kafka集群消费消息。它支持自动和手动提交偏移量,以及手动分配主题分区。消费者组通过负载均衡和容灾策略确保消息的可靠消费。此外,文章还讨论了消费者位置的控制和多线程处理的注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

该文章主要翻译自java类KafkaProducer的Doc文档,基于Kafka2.3版本,Kafka客户端2.3.0版本

1、官方Doc链接如下

https://kafka.apache.org/23/javadoc/index.html?org/apache/kafka/clients/consumer/KafkaConsumer.html


2、Kafka的Maven依赖如下
<!-- https://mvnrepository.com/artifact/org.apache.kafka/kafka-clients -->
<dependency>
    <groupId>org.apache.kafka</groupId>
    <artifactId>kafka-clients</artifactId>
    <version>2.3.0</version>
</dependency>


3、基于官方文档整理的内容

KafkaConsumer用来从kafka集群消费消息。KafkaConsumer会自动处理所链接节点的失效,自动适应主题(topic)分区在kafka集群内的转移,自动利用 消费者分组(consumer groups) 来实现消息消费的负载均衡。
KafkaConsumer与kafka集群的节点之间维持一个TCP链接,不再使用的KafkaConsumer需要关闭,否则这个TCP链接就泄露了。需要注意的是 KafkaConsumer不是线程安全 的。


跨版本兼容

这个版本的KafkaConsumer支持kafka 0.10.0 版本,低与这个版本的kafka不兼容。


偏移量和消费者位置

kafka集群将消息存储在集群中的一个个分区上,这一个个分区中的消息在分区中都有一个唯一的用数字表示的位置,也就是偏移量(Offsets)。消费者就是顺着分区中消息的这个偏移量,一个接着一个的消费消息的。那么如何得知当前消费者已经消费到哪个消息了呢?其实就是根据消息的偏移量来得知的,是消息的偏移量+1,比如当前消费者消费到了偏移量为4的消息,那么消费者位置就是5,就像是java遍历数组的操作,遍历到第4个数组元素的时候,位置是5,这就是消费者位置。
对于消费者来说,有两个位置概念需要理解;

  • 消费者位置:也就是上述的那个位置,表示当前消费者消费到了哪个消息,每次调用 poll() 方法消费消息的时候这个值都会自动往上加,类似上述所说遍历数组的操作。
  • 已提交位置(committed position):这个主要是为了容灾用的,因为消费者和和kafka集群中间的网络连接可能中断,上述文章也说了,消费者会自动重连到kafka集群,但是重连之后消费者如何才能知道上次处理到哪条消息了呢?这个时候 已提交位置 就派上用场了。已提交位置 是保存在kafka集群那里的,不是保存在消费者那里。当消费者连接到kafka集群的时候,kafka集群会自动检测连接到它的消费者是否在它那里有 已提交位置 ,如果有的话,kafka集群就会告诉消费者从哪里继续开始消费消息,否则的话就由消费者自己决定从哪里开始消费消息。读者可能会问,已提交位置 是永久的吗?答案是:不是。在一定时间内,kafka集群如果检测到某个 已提交位置 所对应的消费者已经不再与它有通信了,则这个 已提交位置 就会被kafka集群清理掉。已提交位置 是怎么来的呢?答案是:消费者通过一定的配置自动提交这个 已提交位置 ,或者通过调用 commitSync 或者 commitAsync 方法手动提交。

这些不同的概念就给了消费者一些手段来自主决定哪些消息是已经消费了的,下文会有更详细的介绍。


消费者组和主题订阅

group.id:这是一个KafkaConsumer的配置,拥有同样 group.id 的消费者在kafka集群看来就是属于一个组的。

消费者组中的每个消费者都能通过调用 subscribe() 方法来自主决定订阅哪些主题。kafka集群将把被订阅主题中的某个消息发送到订阅这个主题的某个消费者组中的 一个 消费者,kafka集群通过将主题所涉及的分区均匀的分给订阅这个主题的消费者组中的消费者来实现这个功能。比如:如果一个主题有 4 个分区,一个消费者组有 2 个消费者并且这个消费者组订阅了这个主题,那么这个消费者组中的每个消费者都将被分配到 2 个分区。
消费者组中消费者的关系是动态的,也就是说,如果消费者组中的某个消费者失效了,那么分配给它的那些分区就会被自动重新分配给这个消费者组中的其他消费者,也就是实现了容灾。同样的,如果某个消费者组中新加入了一个消费者,那么就会从这个消费者组中的其他消费者身上取一些分区给这个新加入的消费者,也就是实现了负载均衡。下文有这方面的详细讨论。类似的负载均衡也会在主题增加了新的分区或者一个新主题被创建并且被订阅的时候发生。
另外,当消费者组内的负载均衡发生时,消费者可以通过 ConsumerRebalanceListener 来获取通知。消费者也可以通过调用 assign() 方法手动指定主题分区,若手动指定分区,则消费者组内分区的动态分配和负载均衡将会被禁用。


消费者失效检测
  • session.timeout.ms:消费者在调用 poll() 方法后会自动加入到消费者组中(消费者组和组内消费者信息是保存在kafka集群端的,调用poll()方法后kafka集群会自动创建、保存和维护相应消费者组信息)。poll() 方法会自动维持消费者和kafka集群的链接,也就是保活KafkaConsumer。只要消费者持续调用 poll() 方法,消费者就会一直待在消费者组内,并从kafka集群消费消息。保活的实现原理就是KafkaConsumer会持续向kafka集群发送 心跳(heartbeats) 。如果消费者失效了,不能在一定时间内向kafka集群发送心跳,kafka集群就会认为这个客户端掉线,并把分配给这个客户端的分区自动负载均衡给消费者组内的其他消费者。这里,这个发送心跳的时间间隔就是这个配置的值。
  • max.poll.interval.ms:某些情况下,消费者也会出现 活锁(livelock) 的情况,活锁的意思就是消费者正常的向kafka集群发送心跳来保活,但就是不调用 poll() 方法消费消息,也就是俗话说的 zhanzhemaokengbulashi,这种情况下消费者白白占着kafka集群的分区和资源,但是不进行实际的消息消费操作,为了检测这种情况,可以配置 max.poll.interval.ms 参数,这个参数控制消费者调用 poll() 方法的最大时间间隔,如果消费者在这个时间内没有调用 poll() 方法消费消息,则消费者会 主动 离开消费者组,把占着的分区让给其他在消费的消费者。如果发生了这种情况,主动失效的那个消费者在调用 commitSync() 后会报一个 CommitFailedException 的异常。这是官方KafkaConsumer的一种安全机制,只有活着的消费者才能提交 已提交位置 并从kafka集群消费消息,所以为了一直待在消费者组里,消费者就必须持续调用 poll() 消费消息。
    KafkaConsumer调用 poll() 方法的行为可以被两个配置控制:
  1. max.poll.interval.ms:该配置含义如上述解释,默认值:300000。个人不建议更改这个配置,保持默认就好。这个参数对 poll() 方法的具体影响就是:增大该配置,可以给消费者更多时间来处理 poll() 方法返回的消息,但是可能会延迟kafka集群可能发生的自动分区负载均衡,因为消费者只有在调用 poll() 方法后才会参与分区负载均衡,同时会允许消费者更少调用 poll() 方法,从而导致kafka集群内存储的消息无法被及时处理。减小该配置,可能会导致消费者因为无法及时处理上一个 poll() 方法返回的消息而无法在这个时间内调用下一个 poll() 方法,然后如上述解释,主动退出消费者组,从而导致一系列其他问题。所以该配置保持默认就好。
  2. max.poll.records:该配置决定每次调用 poll() 方法最多返回的消息的个数,默认值:500。增大该配置可能会导致消费者无法及时处理消息,减小该配置可能会导致kafka集群端存储的消息无法被及时处理。该参数保持默认就好。

官方Doc代码示例
  1. 自动 已提交位置
     Properties props = new Properties();
     props.setProperty("bootstrap.servers", "localhost:9092");
     props.setProperty("group.id", "test"
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值