6. Análisis del código fuente del servidor de registro del servicio Nacos (5)

El análisis anterior TaskExecuteEnginey sus dos subcategorías NacosDelayTaskExecuteEnginey NacosExecuteTaskExecuteEngine. Los amigos que no lo han visto pueden hacer clic aquí para ver 5. Análisis del código fuente del servidor de registro del servicio Nacos (4) . Este artículo analiza desde NacosTaskel principio y analiza la lógica posterior.

Análisis de tareas

NacosTaskSólo hay un método boolean shouldProcess(), que es juzgar si se debe ejecutar.

Tiene dos subclases abstractas, a saber AbstractExecuteTaskyAbstractDelayTask

NacosTarea.png

AbstractExecuteTaskLa implementación es muy simple, solo trueejecute según sea necesario.

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

AbstractDelayTaskEs de ejecución retardada, por lo que tiene un juicio de mecanismo de retardo.

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

Aquí todavía usamos el análisis anterior PushDelayTaskpara analizar el efecto de este método.

@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);
}

NacosDelayTaskExecuteEngineEsto también corresponde al análisis anterior NacosExecuteTaskExecuteEngine. Debido a NacosExecuteTaskExecuteEngineque no hay necesidad de demorar, el valor predeterminado es ejecutar, uno por uno. Y NacosDelayTaskExecuteEnginehabrá un procesamiento demorado, principalmente por procesamiento fallido y demorado. Dado que es una falla, 100 ms sigue siendo un intervalo corto para el procesamiento fallido, por lo que se coloca en la colección y luego se procesa de manera uniforme después de que finaliza el tiempo de demora. El tiempo de demora aquí es de 1 segundo.

Sigamos con el análisis del último código.

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

El primer paso es obtener delayTaskEngine.getPushExecutor(), rastrear y analizar esta clase, y encontrar que el constructor la pasa. Haciendo un seguimiento, puede ver que esta clase está administrada spring. inyectado PushExecutorDelegate_

La traducción de esta Delegatepalabra es encomendada, indicando que este es el modo encomendado. Eche un vistazo a algunas variables miembro y métodos principales de esta clase.

// 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;
}

El código fuente analizado en este artículo 2.2.0es, naturalmente, el empuje de la versión rpc. En cuanto a por qué se abandonó , puede leer las citas en updel primer artículo 1, Análisis del código fuente del cliente de registro del servicio Nacos , y no lo explicaré aquí.

Seguimos analizando a lo largo del tren del pensamientocom.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();
    }
}

Uno se construye aquí NotifySubscriberRequest. Recuerda el código que analizamos anteriormente. Uno Requestrepresenta un tipo de solicitud de red y debe haber un Handlerprocesamiento. Aquí com.alibaba.nacos.client.naming.remote.gprc.NamingPushRequestHandlerviene el trato.

Puedes ver este paquete en clientel paquete. Es decir, grpcel procesamiento de flujos bidireccionales. La solicitud de servicio se puede aceptar directamente y el cliente puede procesarla directamente. Echemos un breve vistazo al procesamiento del cliente.

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;
}

Resumir

El contenido de este artículo no es mucho, se trata principalmente del contenido del último artículo. En el próximo artículo, volveré a ordenar el servidor de registro. Después de todo, se divide en varios capítulos para explicar, y los puntos de conocimiento están relativamente fragmentados. Puede hacer clic en el enlace de abajo para ver directamente.

7. Análisis del código fuente del servidor de registro del servicio Nacos (resumen)

Supongo que te gusta

Origin blog.csdn.net/qq_34626094/article/details/130516989
Recomendado
Clasificación