kafka消费者(三):ConsumerCoordinator

在kafka的消费者中通过ConsumerCoordinator组件实现与服务端的GroupCoordinator的交互,ConsumerCoordinator集成了AbstractCoordinator抽象类。AbstractCoordinator的核心字段如下:
 

public abstract class AbstractCoordinator implements Closeable {
    //心跳任务的辅助类,记录了两次发送心跳消息的间隔(interval),最近发送心跳的时间(lastHeartbeatSend)
    //最近收到心跳的时间(lastHeartbeatReceive),过期时间(timeout),心跳任务重置时间(lastSessionReset)
    //还提供了计算下次发送心跳的时间方法(timeToNextHeartbeat),是否过期的方法(sessionTimeoutExpired)
    private final Heartbeat heartbeat;
    //定时任务,负责发送心跳请求和心跳响应处理,会添加到前面介绍的ConsumerNetworkClient
    private final HeartbeatTask heartbeatTask;
    private final int sessionTimeoutMs;
    private final GroupCoordinatorMetrics sensors;
    //当前消费者组ID
    protected final String groupId;
    //ConsumerNetworkClient对象,负责网络通信和执行定时任务
    protected final ConsumerNetworkClient client;
    protected final Time time;
    protected final long retryBackoffMs;
    //标志是否需要执行发送JoinGroupRequest请求前的准备操作
    private boolean needsJoinPrepare = true;
    //是否重亲发送JoinGroupRequest请求的条件之一
    private boolean rejoinNeeded = true;
    //记录服务端GroupCoordinator所在Node的节点
    protected Node coordinator;
    //服务端GroupCoordinator返回的分配给消费者唯一ID
    protected String memberId;
    protected String protocol;
    //服务端GroupCoordinator返回的年代信息,用来区分两次rebalance操作。
    //由于网络延迟等问题,在执行Rebalance操作时可能受到上次rebalance过期的请求,避免这种干扰,每次rebalance操作都会递增generation的值
    protected int generation;
}

下面是ConsumerCoordinator的核心字段:

public final class ConsumerCoordinator extends AbstractCoordinator {
    //PartitionAssignor列表。在消费者发送的JoinGroupRequest请求中包含了消费者自身支持的PartitionAssignor信息。
    //GroupCoordinator会从所有消费者中支持的分配策略中选择一个,通知leader使用此分配策略进行分区分配。由partition.assignment.strategy参数配置。
    private final List<PartitionAssignor> assignors;
    //Kafka元数据
    private final Metadata metadata;
    private final ConsumerCoordinatorMetrics sensors;
    //订阅状态
    private final SubscriptionState subscriptions;
    //提交offset任务的callback
    private final OffsetCommitCallback defaultOffsetCommitCallback;
    //是否开启自动提交offset
    private final boolean autoCommitEnabled;
    //自动提交offset的定时任务
    private final AutoCommitTask autoCommitTask;
    //ConsumerInterceptors集合
    private final ConsumerInterceptors<?, ?> interceptors;
    //标识是否排除内部topic
    private final boolean excludeInternalTopics;
    //用来储存Metadata的快照信息,主要用来检测Topic是否发生了分区数量的变化。
    //在ConsumerCoordinator的构造方法中,会为metadata添加一个监听器,当metadata更新时会做以下事情:
    //1. 如果是AUTO_PARTTERN模式,则使用用户自定义的正则表达式过滤Topic,得到需要订阅的Topic集合后,设置到SubscriptionState的subscription集合和groupSubscription集合中。
    //如果是AUTO_PATTERN和AUTO_TOPICS模式,为当前metadata做一个快照,这个快照底层使用map记录每个topic中partition的个数。
    //把新老快照做个对比,如果发生变化,就表示消费者订阅的topic发生分区数量的变化,就把subscriptionState的needsPartitionAssignment字段设置为true,需要重新进行分区分配。
    //使用metadataSnapshot字段记录变化后的新快照
    private MetadataSnapshot metadataSnapshot;
    //存储metadata的快照信息,不过是用来检测partition分区的过程中有没有分区数量变化。
    //在leader消费者开始分配分区操作前,使用这个字段记录metadata快照;受到syncGroupResponse后,会比较此字段记录的快照与当前Metadata是否发生变化。如果发生变化,就要重新进行分区分配。
    private MetadataSnapshot assignmentSnapshot;
}

下面分析metadata的listener的具体实现:

private void addMetadataListener() {
    this.metadata.addListener(new Metadata.Listener() {
        @Override
        public void onMetadataUpdate(Cluster cluster) {
            //AUTO_PATTERN模式的处理
            if (subscriptions.hasPatternSubscription()) {

                Set<String> unauthorizedTopics = new HashSet<String>();
                //权限验证
                for (String topic : cluster.unauthorizedTopics()) {
                    if (filterTopic(topic))
                        unauthorizedTopics.add(topic);
                }
                if (!unauthorizedTopics.isEmpty())
                    throw new TopicAuthorizationException(unauthorizedTopics);

                final List<String> topicsToSubscribe = new ArrayList<>();
                //通过pattern匹配topic
                for (String topic : cluster.topics())
                    if (filterTopic(topic))
                        topicsToSubscribe.add(topic);
                //更新subscription集合、groupSubscription集合、assignment集合
                subscriptions.changeSubscription(topicsToSubscribe);
                //更新metadata需要记录元数据的topic集合
                metadata.setTopics(subscriptions.groupSubscription());
            } else if (!cluster.unauthorizedTopics().isEmpty()) {
                throw new TopicAuthorizationException(new HashSet<>(cluster.unauthorizedTopics()));
            }

            // c检测是否为ATUO_PATTERN或者AUTO_TOPICS模式
            if (subscriptions.partitionsAutoAssigned()) {
                //创建快照
                MetadataSnapshot snapshot = new MetadataSnapshot(subscriptions, cluster);
                //对比快照
                if (!snapshot.equals(metadataSnapshot)) {
                    //记录快照
                    metadataSnapshot = snapshot;
                    //更新needsPartitionAssignment字段为true,表示需要进行分区分配
                    subscriptions.needReassignment();
                }
            }

        }
    });
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值