Kafka源码之KafkaConsumer分析之Rebalance

我们先来看一下哪些情况会发生Rebalance操作:
1、有新的消费者加入ConsumerGroup
2、有消费者宕机下线。
3、有消费者主动退出Consumer Group
4、Consumer Group订阅的任一Topic出现分区数量的变化
5、消费者调用unsubscribe取消对某Topic的订阅
下面对Reblance操作的具体实现进行分析
第一阶段
Rebalance操作的第一步就是查找GroupCoordinator,这个阶段消费者会向Kafka集群中的任意一个Broker发送GroupCoordinatorRequest请求,并处理返回的GroupCoordinatorResponse,
1、首先检测是否需要重新查找GroupCoordinator,主要是检查coordinator字段是否为空以及与GroupCoordinator之间的连接是否正常。

    public boolean coordinatorUnknown() {
    	//检查coordinator字段是否为空
        if (coordinator == null)
            return true;
		//检测连接是否正常
        if (client.connectionFailed(coordinator)) {
        	//将unsent集合中对应的请求清空并将coordinator字段设置为null
            coordinatorDead();
            return true;
        }

        return false;
    }

2、查找集群负载最低的Node节点,并创建GroupCoordinatorRequest请求。调用client.send方法将请求放入unsent队列中等待发送,并返回RequestFuture对象。
3、调用ConsumerNetworkClient.pool方法,将GroupCoordinatorRequest请求发送出去。
4、检测检查RequestFuture对象的状态。如果出现RetriableException异常,则调用ConsuemerNetworkClient.awaitMetadataUpdate()方法阻塞更新Metadata中的记录的集群元数据后跳转到步骤一
5、如果成功找到GroupCoordinator节点,但是网络连接失败,则将其unsent中对应的请求清空,并将coordinator字段置为1,退避一段时间后跳转到步骤1执行
下面我们就进入源码看一下这个过程:

public void ensureCoordinatorReady() {
		//把是否需要查找GroupCoordinator作为循环条件
        while (coordinatorUnknown()) {
        	//将GroupCoordinatorRequest放到unsent队列里面等待发送
            RequestFuture<Void> future = sendGroupCoordinatorRequest();
            //阻塞获取response
            client.poll(future);
			//判断是否串异常
            if (future.failed()) {
            	//如果是这个异常,那么阻塞等待metadata更新
                if (future.isRetriable())
                    client.awaitMetadataUpdate();
                else
                    throw future.exception();
                    //如果获取失败,那么清空coordinator,等待一段时间再去请求
            } else if (coordinator != null && client.connectionFailed(coordinator)) {
                // we found the coordinator, but the connection has failed, so mark
                // it dead and backoff before retrying discovery
                coordinatorDead();
                time.sleep(retryBackoffMs);
            }

        }
    }

下面我们看里面的方法的具体实现:

private RequestFuture<Void> sendGroupCoordinatorRequest() {
        // 找到负载最小的节点
        Node node = this.client.leastLoadedNode();
        if (node == null) {
        	//如果没有找到返回一个异常结束
            return RequestFuture.noBrokersAvailable();
        } else {
            // 常见要给request
            GroupCoordinatorRequest metadataRequest = new GroupCoordinatorRequest(this.groupId);
            //调用ConsumerNetworkClient.send添加到unsent集合中
            return client.send(node, ApiKeys.GROUP_COORDINATOR, metadataRequest)
                    .compose(new RequestFutureAdapter<ClientResponse, Void>() {
                        @Override
                        public void onSuccess(ClientResponse response, RequestFuture<Void> future) {
                            handleGroupMetadataResponse(response, future);
                        }
                    });
        }
    }

服务端会根据发出的请求返回要给Response,当接收到Response的时候需要对它进行处理:
1、调用coordinatorUnknown检测是否已经找到GroupCoordinator且成功连接。如果是则忽略此Response,因为会有重发机制
2、解析Response来解析GroupCoordinator
3、构建Node对象赋值给coordinator字段,并尝试与GroupCoordinator建立连接。
4、启动HeartbeatTask定时任务
5、最后调用RequestFuture.complete方法将正常收到的GroupCoordinatorResponse的事件传播出去
6、如果收到的Response中的错误码不为NONE,则将异常事件传播出去

private void handleGroupMetadataResponse(ClientResponse resp, RequestFuture<Void> future) {
        log
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值