问题:
1.位移越界原因?
2.kafka存储位移过期设置?
消费者组
消费者(Consumer)订阅kafka中的主题topic,从订阅主题拉取消息;
消费者组(group.id):每一个消费者属于一个消费者组,同一个主题的同一分区只能被一个消费者组中的一个消费者消费。让整体消费能力有横向伸缩性。
增加消费者组内消费者数量可以提高消费能力,但如果消费者组内消费者数量大于分区数,那么将有一个消费者分配不到任何分区而无法消费消息。
订阅主题和分区
1-集合订阅方式–AUTO_TOPICS
//按照topic订阅,如 subscribe(Arrays.asList(topic1,topic2))
void subscribe(Collection<String> topics);
void subscribe(Collection<String> topics, ConsumerRebalanceListener listener);
2-正则表达式订阅方式–AUTO_PATTERN
//按照正则表达式订阅,如:subscribe(Pattern.compile("topic-*"))
void subscribe(Pattern pattern);
void subscribe(Pattern pattern, ConsumerRebalanceListener listener);
3-指定分区订阅方式 --USER_ASSIGNED
void assign(Collection<TopicPartition> partitions);
//参数,表示主题和分区
public final class TopicPartition implements Serializable {
private final int partition;
private final String topic;
}
partitionsFor()
//消费者获取主题的分区元数据
List<PartitionInfo> partitionsFor(String topic);
public class PartitionInfo {
private final String topic; //主题
private final int partition; //分区
private final Node leader; //leader所在位置
private final Node[] replicas; //AR集合
private final Node[] inSyncReplicas; // ISR集合
private final Node[] offlineReplicas; //OSR集合
}
4-取消订阅
consumer.unsubscribe();
consumer.subscribe(new ArraysList<String>());
consumer.assign(new ArraysList<TopicPartition>());
消息消费
消息消费一般有两种方式:推和拉,kafka是拉模式,消息消费是一个不断轮询的过程,调用poll()方法。
分为按主题消费和按分区消费
// 在消费这的缓冲区没有可用数据时发生阻塞,设置值取决于对响应速度要求
public ConsumerRecords<K, V> poll(Duration timeout)
//按分区消费
List<ConsumerRecord<K, V>> records(TopicPartition partition);
//按主题消费
public Iterable<ConsumerRecord<K, V>> records(String topic);
public class ConsumerRecord<K, V> {
private final String topic;
private final int partition;
private final long offset; //偏移量
private final long timestamp; 时间戳
private final TimestampType timestampType; //时间戳类型
private final int serializedKeySize; //key序列化后的大小,没有则为-1
private final int serializedValueSize; //value序列化后的大小,没有则为-1
private final Headers headers;
private final K key;
private final V value;
private volatile Long checksum; //CRC32的校验值
}
public enum TimestampType {
NO_TIMESTAMP_TYPE(-1, "NoTimestampType"),
CREATE_TIME(0, "CreateTime"), //消息创建的时间戳
LOG_APPEND_TIME(1, "LogAppendTime"); //消息追加到日志的时间戳
}
位移提交
偏移量(offset):对分区而言,每条消息都有唯一的offset,用来表示在分区中对应的位置。
位移(offset):对消费者而言,offset表示消费者消费到分区中某个消息的位置。
在旧消费者客户端,消费位移保存在zookeeper中;新消费者客户端中,消费位移保存在kafka内部主题_consumer_offsets中。
因为有了消费位移的持久化,才使消费者在关闭、崩溃或再均衡的时候可以继续消费,而不是重头消费。
消费位移是按照消费者组指定的。
提交位移是下一次要拉取的消息的偏移量,即已经消费消息的偏移量+1。
位移提交引起消息丢失和重复消费;
1.自动提交
kafka默认提交方式:
自动位移提交动作是在poll()方法的逻辑中完成的,在每次真正向服务端发起拉请求之前会检查是否可以进行位移提交,如果可以,就会提交上一次轮询的位移。
//默认自动提交
enable.auto.commit=true
//定期提交时间默认值是5秒
auto.commit.interval.ms
2.手动提交
1-同步位移提交
//只能提交当前批次对应的position值,
public void commitSync();
//每消费一条就提交一次位移可以用这个方法,但是会耗费性能,很少使用。
//可以按分区粒度同步提交消费位移
public void commitSync(Map<TopicPartition, OffsetAndMetadata> offsets)
2-异步位移提交
异步提交位移在执行的时候消费者线程不会被阻塞
public void commitAsync();
public void commitAsync(OffsetCommitCallback callback);
public void commitAsync(Map<TopicPartition, OffsetAndMetadata> offsets, OffsetCommitCallback callback);
异步提交失败重试会引起重复消费,所以需要设置一个递增的序号来维持异步提交的顺序。
控制或关闭消费
//暂停某分区在拉操作时返回数据给客户端
public void pause(Collection<TopicPartition> partitions)
//恢复
public void resume(Collection<TopicPartition> partitions)
//返回被暂停的分区集合
public Set<TopicPartition> paused()
//调用后跳出poll()逻辑,抛异常WakeupException
public void wakeup()
关闭及释放运行过程中占用的各种系统资源
//设置关闭方法最长执行时间
void close(Duration var1);
//默认30秒
void close();
指定位移提交
消费者组找不到位移的情况:
1.新创建消费者组的时候;
2.消费者组内一个新的消费者订阅了一个新的主题;
3.__consumer_offsets主题中有关这个消费者组的位移信息过期被删除时;
位移越界:知道消费位移但无法从实际的分区中找到。
重置消费位移:
找不到消费位移或者位移越界
auto.offset.reset latest(默认)/earliest /none
seek()
seek()方法只能重置消费者分配到的分区的消费位移,而分区的分配是在poll()方法的调用中实现的,也就是说,在执行seek()方法之前需要先执行一次poll()方法,等分配到分区后才能重置消费位移。
public void seek(TopicPartition partition, long offset)
//获取消费者分区的方法
public Set<TopicPartition> assignment()
//无timeout则取request.timeout.ms 默认值30000
//获取指定分区末尾的消息位移
Map<TopicPartition, Long> endOffsets(Collection<TopicPartition> partitions);
Map<TopicPartition, Long> endOffsets(Collection<TopicPartition> partitions, Duration timeout);
//获取指定分区开始的消息位移
public Map<TopicPartition, Long> beginningOffsets(Collection<TopicPartition> partitions);
public Map<TopicPartition, Long> beginningOffsets(Collection<TopicPartition> partitions, Duration timeout);
//按照时间查询消息位移,返回值是大于等于timestampsToSearch的第一条时间戳
public Map<TopicPartition, OffsetAndTimestamp> offsetsForTimes(Map<TopicPartition, Long> timestampsToSearch);
public Map<TopicPartition, OffsetAndTimestamp> offsetsForTimes(Map<TopicPartition, Long> timestampsToSearch, Duration timeout);
再均衡
再均衡是指分区的所属权从一个消费者转移到另一个消费者的行为,它为消费组具备高可用和伸缩性提供保障,但是在再均衡发生期间,消费者组是无法读取消息的。
另外,当一个分区被重新分配到一个新的消费者,消费者当前状态会丢失,比如消费了某些消息还未提交位移,重新分配后会造成重复消费。
public interface ConsumerRebalanceListener {
//再均衡开始前,消费者停止消费后调用,处理消费位移的提交
void onPartitionsRevoked(Collection<TopicPartition> partitions);
//重新分区后和开始消费前调用
void onPartitionsAssigned(Collection<TopicPartition> partitions);
}
消费者拦截器
KafkaConsumer会在poll()方法返回之前调用onCommit()方法,对消息进行定制话操作;
KafkaConsumer会在提交完消费位移之后调用onCommit()方法
public interface ConsumerInterceptor<K, V> extends Configurable {
ConsumerRecords<K, V> onConsume(ConsumerRecords<K, V> var1);
void onCommit(Map<TopicPartition, OffsetAndMetadata> var1);
void close();
}