前言
应用程序时通过KafkaCOnsumer来订阅主题,并从订阅的主题中拉取消息。
消费者与消费组
与其他消息中间件不同:Kafka的消费概念中有一层消费组概念。每一个消费者都有一个对应的消费组。当消息发送到主题后,只会被投递给订阅它的每个消费组中一个消费者。
消费者与消费组这种模型可以让整体的消费能力具有横向伸缩性。(我们可以增加或减少消费者的个数来提高或降低整体的消费能力)
对于消息中间件而言,一般有两种消息投递模式:点对点模式、发布/订阅模式
一个正常的消费逻辑具有以下步骤
- 配置消费者客户端参数以及创建相应的消费者实例
- 订阅主题
- 拉取消息并消费
- 提交消费位移
- 关闭消费者实例
必要的参数配置
- bootstrap.servers:kafka集群的broker地址清单
- group.id: 消费者属于的消费组的名称
- key.deserializer: 反序列消息key
- value.deserializer: 反序列消息value
订阅主题和分区
创建好消费者之后,我们就需要为该消费者订阅相关的主题了。
我们事先不知道主题中有多少个分区怎么办?kafkaConsumer中的partitionsFor()方法可以查询指定主题的元数据。
PartitionInfo 类定义
String topic;
int partition
Node leader;
Node[] replicas;
Node[] inSyncReplicas;
Node[] offlineReplicas;
leader 表示分区的leader副本所在位置,replicas 代表分区AR集合。inSyncReplicas 表示ISR集合;offlineReplicas OSR集合。
集合订阅、正则表达式订阅、指定分区订阅分表表示三种不同的订阅状态。 是互斥的,消费者只能使用其中的一种。
反序列化
消息消费
kafka中的消费是基于拉模式的。消息的消费一般有两种模式:推模式、拉模式。
消费者所要做的是重复调用poll方法。如果订阅的所有分区中,没有可供消费的消息,那么poll方法返回空的消息集合。
poll方法有一个超时时间参数,用来控制poll方法阻塞的时间,在消费者的缓冲区里没有可用的数据时会发生阻塞。
位移提交
对于Kafka中的分区而言,它的每条消息都有唯一的offset,用来标识消息在分区中的位置。
每次poll的消息,都是没有被消费过的消息集。要做到这点,就需要记录上次消费时的消费位移。
在Kafka中默认的消费位移的提交方式是自动提交的(可配置)。当然这个默认的自动提交不是每消费一条记录就提交一次,而是定期提交(参数可配置)。
随之而来的问题是重复消费和消息丢失。
控制或关闭消费
有些应用场景下我们可能需要暂停某些分区的消费而先消费其他分区,当达到一定条件时再恢复这些分区的消费。
指定位移消费
正是有了消费位移的持久化,才使得消费者在关闭、崩溃、遇到再均衡的时候,可以让接替的消费者能够根据存储的消费位移继续进行消费。
在Kafka中每当消费者查询不到所记录的消费位移时,会根据消费者客户端参数auto.offset.reset配置来决定从何处开始消费。默认值 latest表示从分区末尾开始消费。earliest 从开始处消费。
可以从特定位置开始消费消息,就是KafkaConsumer中的seek方法。