Kafka是一款基于发布与订阅的消息系统。其中消息的订阅以及最终的消费是由Kafka中的消费者来完成。关于Kafka中的消费者,其包含的内容比较多,现在归纳如下:
01、消费者和消费者群组
Kafka消费者从属于消费者群组。一个群组里的消费者订阅的是同一个主题,每个消费者接受主题一部分分区的消息。
往群组里增加消费者是横向伸缩消费能力的主要方式。但是要注意,不要让消费者的数量超过主题分区的数量,多余的消费者只会被闲置。
此外,还可以多个应用程序从同一个主题读取数据。
以上两种方式分别是横向伸缩Kafka消费者和消费者群组。
02、消费者群组和分区再平衡
分区的所有权从一个消费者转移到另一个消费者,这样的行为被称为再平衡。
消费者通过被指派为群组协调器的broker发送心跳来维持它们和群组的从属关系以及它们对分区的所有权关系。
03、创建Kafka消费者
创建一个KafkaConsumer对象与创建KafkaProducer对象类似,要把传给消费者的属性放在Properties对象里。有3个必要的属性:
bootstrap.servers:指定Kafka集群的连接字符串。
key.deserializer、key.deserializer:将指定类的键、值的字节数组转成Java对象。
04、订阅主题
subscribe()方法接收一个主题列表作为参数即可,也可以在调用subscribe()方法时传入一个正则表达式。
05、轮询
消费者必须使用consumer.poll()方法持续对Kafka进行轮询,否则就被认为已经死亡,其分区会被移交给群组里的其他消费者。poll()方法的参数是一个超时时间,用于控制poll()方法的阻塞时间。如果该参数设为0,poll()会立即返回,否则它会在指定的毫秒数内一直等待broker返回数据。
06、提交和偏移量
更新分区当前位置的操作叫作提交。
消费者需要读取每个分区最后一次提交的偏移量,然后从偏移量指定的地方继续处理。
提交的方式主要有以下几种:
1、自动提交
2、提交当前偏移量
3、异步提交
4、同步和异步组合提交
5、提交特定的偏移量
07、再均衡监听器
在为消费者分配新分区或移除旧分区时,要调用subscribe()方法传进去一个ConsumerRebalanceListener实例,以便执行一些应用程序代码。
ConsumerRebalanceListener有两个需要实现的方法:
1、public
void onPartitionsRevoked(Collection< TopicPartition> partitions)方法会在再均衡开始之前和消费者停止读取消息之后被调用。
2、public
void onPartitionsAssigned(Collection< TopicPartition> partitions)方法会在重新分配分区之后和消费者开始读取消息之前被调用。
08、从特定偏移量处开始处理记录
从分区的起始开始读取消息:seekToBegining(Collection< TopicPartition >
tp)
从分区的末尾开始读取消息:seekToEnd (Collection< TopicPartitio>
tp)
如果偏移量是保存在数据库而不是Kafka里,在消费者启动或分配到新分区时,可以使用seek()方法查找保存在数据库里的偏移量。
需要注意,seek()方法只更新我们正在使用的位置。
09、如何退出
如果确定要退出循环,需要通过另一个线程调用consumer.wakeup()方法。如果循环运行在主线程里,可以在ShutdHook里调用该方法。consumer.wakeup()是消费者唯一一个可以从其他线程里安全调用的方法。调用consumer.wakeup()可以退出poll(),并抛出WakeupException()异常,但是并不需要处理WakeupException,因为它只是用于跳出循环的一种方式。
10、反序列化器
消费者需要用到反序列化器把从Kafka接收到的字节数组转化成Java对象。
一般在消费者中使用KafkaAvroDeserializer来反序列化Avro消息。
11、独立消费者
独立消费者不需要订阅主题,取而代之的是为自己分配分区。一个消费者可以订阅主题(并加入消费者群组),或者为自己分配分区,但不能同时做这两件事。
如果主题增加了新的分区,消费者并不会收到通知,因此需要周期性地调用consumer.partitionsFor()方法来检查是否有新分区加入。