6. Nacos サービス登録サーバーのソースコード解析 (5)

前の分析TaskExecuteEngineとその 2 つのサブカテゴリNacosDelayTaskExecuteEngineおよびNacosExecuteTaskExecuteEngine. まだ見ていない友人は、ここをクリックして5. Nacos サービス登録サーバーのソース コード分析 (4)を表示できます。この記事では、NacosTask最初から分析し、その後のロジックを分析します。

タスク分析

NacosTaskboolean shouldProcess()実行するかどうかを判断する方法は 1 つしかありません。

AbstractExecuteTaskの 2 つの抽象サブクラスがあります。AbstractDelayTask

NacosTask.png

AbstractExecuteTask実装は非常に単純で、true必要に応じて実行するだけです。

@Override
public boolean shouldProcess() {
    
    
    return true;
}

AbstractDelayTask遅延実行なので、遅延機構判定をしています。

@Override
public boolean shouldProcess() {
    
    
    // 如果当前时间减去上次时间还未到达任务执行的间隔时间则返回false
    return (System.currentTimeMillis() - this.lastProcessTime >= this.taskInterval);
}
// 抽象类,由子类判断添加的任务是否可以合并
public abstract void merge(AbstractDelayTask task);

ここでは、以前の分析を使用して、PushDelayTaskこの方法の効果を分析します。

@Override
public void merge(AbstractDelayTask task) {
    
    
    if (!(task instanceof PushDelayTask)) {
    
    
        return;
    }
    PushDelayTask oldTask = (PushDelayTask) task;
    if (isPushToAll() || oldTask.isPushToAll()) {
    
    
        // 可以push到所有的的这一类,无需特殊处理
        pushToAll = true;
        targetClients = null;
    } else {
    
    
        // 设置个集合,将连接放入,后续要一个个的推,这部分是针对失败的数据
        targetClients.addAll(oldTask.getTargetClients());
    }
    setLastProcessTime(Math.min(getLastProcessTime(), task.getLastProcessTime()));
    Loggers.PUSH.info("[PUSH] Task merge for {}", service);
}

これは、以前の分析にNacosDelayTaskExecuteEngineも対応していますNacosExecuteTaskExecuteEngineNacosExecuteTaskExecuteEngine遅延する必要がないため、デフォルトでは 1 つずつ実行されます。またNacosDelayTaskExecuteEngine、主に失敗した遅延処理のために、遅延処理が発生します。失敗なので100msはまだ処理失敗間隔が短いのでコレクションに入れ、遅延時間経過後に一律に処理する.ここでの遅延時間は1秒である.

最後のコードの分析を続けましょう

delayTaskEngine.getPushExecutor().doPushWithCallback(each, subscriber, wrapper,
                        new ServicePushCallback(each, subscriber, wrapper.getOriginalData(), delayTask.isPushToAll()));

最初のステップは、このクラスを取得delayTaskEngine.getPushExecutor()、追跡、分析し、コンストラクタによって渡されたことを確認することです。追跡すると、このクラスが managed であることがわかりますspring注入されたPushExecutorDelegate

このDelegate単語の翻訳は委託されており、これが委託モードであることを示しています。このクラスのいくつかのメンバー変数とコア メソッドを見てみましょう。

// rpc执行类,V2版本使用
private final PushExecutorRpcImpl rpcPushExecuteService;
// udp执行类,V1版本使用
private final PushExecutorUdpImpl udpPushExecuteService;

public PushExecutorDelegate(PushExecutorRpcImpl rpcPushExecuteService, PushExecutorUdpImpl udpPushExecuteService) {
    
    
    this.rpcPushExecuteService = rpcPushExecuteService;
    this.udpPushExecuteService = udpPushExecuteService;
}

private PushExecutor getPushExecuteService(String clientId, Subscriber subscriber) {
    
    
    Optional<SpiPushExecutor> result = SpiImplPushExecutorHolder.getInstance()
        .findPushExecutorSpiImpl(clientId, subscriber);
    if (result.isPresent()) {
    
    
        return result.get();
    }
    // use nacos default push executor
    // 根据连接的客户端id识别是由upd推送还是rpc推送
    return clientId.contains(IpPortBasedClient.ID_DELIMITER) ? udpPushExecuteService : rpcPushExecuteService;
}

この記事で分析したソース コードは2.2.0、当然 rpc バージョンのプッシュです。断念した理由については、upd第1回の記事1 Nacosサービス登録クライアントのソースコード解析 の引用を読めばわかるので、ここでは説明しません。

私たちは思考の流れに沿って分析を続けますcom.alibaba.nacos.naming.push.v2.executor.PushExecutorRpcImpl#doPushWithCallback

@Override
public void doPushWithCallback(String clientId, Subscriber subscriber, PushDataWrapper data,
                               NamingPushCallback callBack) {
    
    
    // 获取服务信息
    ServiceInfo actualServiceInfo = getServiceInfo(data, subscriber);
    callBack.setActualServiceInfo(actualServiceInfo);
    // 构建一个NotifySubscriberRequest,通过grpc向客户端发送信息
    pushService.pushWithCallback(clientId, NotifySubscriberRequest.buildNotifySubscriberRequest(actualServiceInfo),
                                 callBack, GlobalExecutor.getCallbackExecutor());
}

public void pushWithCallback(String connectionId, ServerRequest request, PushCallBack requestCallBack,
                             Executor executor) {
    
    
    // 拿到客户端的连接
    Connection connection = connectionManager.getConnection(connectionId);
    if (connection != null) {
    
    
        try {
    
    
            // 发送异步请求
            connection.asyncRequest(request, new AbstractRequestCallBack(requestCallBack.getTimeout()) {
    
    

                @Override
                public Executor getExecutor() {
    
    
                    return executor;
                }

                @Override
                public void onResponse(Response response) {
    
    
                    if (response.isSuccess()) {
    
    
                        requestCallBack.onSuccess();
                    } else {
    
    
                        requestCallBack.onFail(new NacosException(response.getErrorCode(), response.getMessage()));
                    }
                }

                @Override
                public void onException(Throwable e) {
    
    
                    requestCallBack.onFail(e);
                }
            });
        } catch (ConnectionAlreadyClosedException e) {
    
    
            connectionManager.unregister(connectionId);
            requestCallBack.onSuccess();
        } catch (Exception e) {
    
    
            Loggers.REMOTE_DIGEST
                .error("error to send push response to connectionId ={},push response={}", connectionId,
                       request, e);
            requestCallBack.onFail(e);
        }
    } else {
    
    
        requestCallBack.onSuccess();
    }
}

1 つはここに建てられますNotifySubscriberRequest前に分析したコードを思い出してください。1 つはRequestネットワーク要求のタイプを表し、1 つの処理が必要ですHandlerこれが取引com.alibaba.nacos.client.naming.remote.gprc.NamingPushRequestHandlerです。

clientこのパッケージはパッケージに表示されます。つまり、grpc双方向ストリームの処理です。サービス要求は直接受け入れられ、クライアントはそれを直接処理できます。クライアントの処理を簡単に見てみましょう。

public class NamingPushRequestHandler implements ServerRequestHandler {
    
     ?
 ? ?private final ServiceInfoHolder serviceInfoHolder;
 ? ?public NamingPushRequestHandler(ServiceInfoHolder serviceInfoHolder) {
    
    
 ? ? ? ?this.serviceInfoHolder = serviceInfoHolder;
 ?  }
 ? ?
 ? ?@Override
 ? ?public Response requestReply(Request request) {
    
    
 ? ? ? ?if (request instanceof NotifySubscriberRequest) {
    
    
 ? ? ? ? ? ?NotifySubscriberRequest notifyRequest = (NotifySubscriberRequest) request;
 ? ? ? ? ? ?// 处理逻辑
 ? ? ? ? ? ?serviceInfoHolder.processServiceInfo(notifyRequest.getServiceInfo());
 ? ? ? ? ? ?return new NotifySubscriberResponse();
 ? ? ?  }
 ? ? ? ?return null;
 ?  }
}
?
public ServiceInfo processServiceInfo(ServiceInfo serviceInfo) {
    
    
 ? ?String serviceKey = serviceInfo.getKey();
 ? ?if (serviceKey == null) {
    
    
 ? ? ? ?return null;
 ?  }
 ? ?// 获取老的服务
 ? ?ServiceInfo oldService = serviceInfoMap.get(serviceInfo.getKey());
 ? ?if (isEmptyOrErrorPush(serviceInfo)) {
    
    
 ? ? ? ?//empty or error push, just ignore
 ? ? ? ?return oldService;
 ?  }
 ? ?// 放入客户端的缓存
 ? ?serviceInfoMap.put(serviceInfo.getKey(), serviceInfo);
 ? ?// 对比下是否发生改变
 ? ?boolean changed = isChangedServiceInfo(oldService, serviceInfo);
 ? ?if (StringUtils.isBlank(serviceInfo.getJsonFromServer())) {
    
    
 ? ? ? ?serviceInfo.setJsonFromServer(JacksonUtils.toJson(serviceInfo));
 ?  }
 ? ?MetricsMonitor.getServiceInfoMapSizeMonitor().set(serviceInfoMap.size());
 ? ?if (changed) {
    
    
 ? ? ? ?NAMING_LOGGER.info("current ips:({}) service: {} -> {}", serviceInfo.ipCount(), serviceInfo.getKey(),
 ? ? ? ? ? ? ? ? ? ? ? ? ? JacksonUtils.toJson(serviceInfo.getHosts()));
 ? ? ? ?// 若改变,发送改变事件
 ? ? ? ?NotifyCenter.publishEvent(new InstancesChangeEvent(notifierEventScope, serviceInfo.getName(), serviceInfo.getGroupName(),
 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? serviceInfo.getClusters(), serviceInfo.getHosts()));
 ? ? ? ?// 磁盘缓存也写一份
 ? ? ? ?DiskCache.write(serviceInfo, cacheDir);
 ?  }
 ? ?return serviceInfo;
}

要約する

この記事の内容は多くはなく、主に前回の記事の内容についてです。次の記事では、登録サーバーをもう一度整理しますが、結局のところ、説明するためにいくつかの章に分かれており、知識のポイントは比較的断片化されています。以下のリンクをクリックして直接表示できます。

7. Nacos サービス登録サーバーのソースコード分析 (まとめ)

おすすめ

転載: blog.csdn.net/qq_34626094/article/details/130516989