nacos源码阅读

一.客户端注册服务源码(1.4.1版本)

主要流程

1.NacosAutoServiceRegistration.register()
2.NacosServiceRegistry.register()
3.NacosNamingService.registerInstance()
4.NamingProxy.registerService()
5.NamingProxy.reqApi()

流程源码阅读

1.NacosAutoServiceRegistration.register()


package com.alibaba.cloud.nacos.registry;

public class NacosAutoServiceRegistration
		extends AbstractAutoServiceRegistration<Registration> {

	@Override
	protected void register() {
		//判断是否是禁用
		if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
			log.debug("Registration disabled.");
			return;
		}
		//判断端口是否小于0
		if (this.registration.getPort() < 0) {
			this.registration.setPort(getPort().get());
		}
		//这里调用的是AbstractAutoServiceRegistration register方法
		super.register();
	}

}

public abstract class AbstractAutoServiceRegistration<R extends Registration>
		implements AutoServiceRegistration, ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {
	protected void register() {
		//这里serviceRegistry是NacosNamingService
		this.serviceRegistry.register(getRegistration());
	}

2.NacosNamingService.registerInstance()

	
	@Override
	public void register(Registration registration) {

		if (StringUtils.isEmpty(registration.getServiceId())) {
			log.warn("No service to register for nacos client...");
			return;
		}
		//获取NamingService
		NamingService namingService = namingService();
		String serviceId = registration.getServiceId();
		String group = nacosDiscoveryProperties.getGroup();
		//获取要注册的实例信息
		Instance instance = getNacosInstanceFromRegistration(registration);

		try {
			//进行服务端注册(重点)
			namingService.registerInstance(serviceId, group, instance);
			log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,
					instance.getIp(), instance.getPort());
		}
		catch (Exception e) {
			log.error("nacos registry, {} register failed...{},", serviceId,
					registration.toString(), e);
			// rethrow a RuntimeException if the registration is failed.
			// issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
			rethrowRuntimeException(e);
		}
	}

3.NacosNamingService.registerInstance()


	//NacosNamingService初始化
    private void init(Properties properties) throws NacosException {
        ValidatorUtils.checkInitParam(properties);
        this.namespace = InitUtils.initNamespaceForNaming(properties);
        InitUtils.initSerialization();
        initServerAddr(properties);
        InitUtils.initWebRootContext(properties);
        initCacheDir();
        initLogName(properties);
        //初始化一个serverProxy 主要用于与服务端交互 发起http请求(@1)
        this.serverProxy = new NamingProxy(this.namespace, this.endpoint, this.serverList, properties);
        //处理心跳的处理器(@2)
        this.beatReactor = new BeatReactor(this.serverProxy, initClientBeatThreadCount(properties));
        //处理服务更新的处理器(@3 )
        this.hostReactor = new HostReactor(this.serverProxy, beatReactor, this.cacheDir, isLoadCacheAtStart(properties),
                isPushEmptyProtect(properties), initPollingThreadCount(properties));
    }
    public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    	//检查一些不合理的设置
        NamingUtils.checkInstanceIsLegal(instance);
        String groupedServiceName = NamingUtils.getGroupedName(serviceName, groupName);
        //判断实例是否是临时的
        if (instance.isEphemeral()) {
        	//构建心跳需要的信息
            BeatInfo beatInfo = beatReactor.buildBeatInfo(groupedServiceName, instance);
            //开启心跳实例线程(@2)
            beatReactor.addBeatInfo(groupedServiceName, beatInfo);
        }
        //构建请求信息并发送注册请求
        serverProxy.registerService(groupedServiceName, groupName, instance);
    }

4.NamingProxy.registerService()

  public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
        
        NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance: {}", namespaceId, serviceName,
                instance);
        //构建请求信息
        final Map<String, String> params = new HashMap<String, String>(16);
        params.put(CommonParams.NAMESPACE_ID, namespaceId);
        params.put(CommonParams.SERVICE_NAME, serviceName);
        params.put(CommonParams.GROUP_NAME, groupName);
        params.put(CommonParams.CLUSTER_NAME, instance.getClusterName());
        params.put("ip", instance.getIp());
        params.put("port", String.valueOf(instance.getPort()));
        params.put("weight", String.valueOf(instance.getWeight()));
        params.put("enable", String.valueOf(instance.isEnabled()));
        params.put("healthy", String.valueOf(instance.isHealthy()));
        params.put("ephemeral", String.valueOf(instance.isEphemeral()));
        params.put("metadata", JacksonUtils.toJson(instance.getMetadata()));
        //发起请求
        reqApi(UtilAndComs.nacosUrlInstance, params, HttpMethod.POST);
        
    }

5.NamingProxy.reqApi()

//这封装了对服务端请求的方法
 public String reqApi(String api, Map<String, String> params, Map<String, String> body, List<String> servers,
            String method) throws NacosException {
        
        params.put(CommonParams.NAMESPACE_ID, getNamespaceId());
        
        if (CollectionUtils.isEmpty(servers) && StringUtils.isBlank(nacosDomain)) {
            throw new NacosException(NacosException.INVALID_PARAM, "no server available");
        }
        
        NacosException exception = new NacosException();
        
        if (StringUtils.isNotBlank(nacosDomain)) {
            for (int i = 0; i < maxRetry; i++) {
                try {
                    return callServer(api, params, body, nacosDomain, method);
                } catch (NacosException e) {
                    exception = e;
                    if (NAMING_LOGGER.isDebugEnabled()) {
                        NAMING_LOGGER.debug("request {} failed.", nacosDomain, e);
                    }
                }
            }
        } else {
            Random random = new Random(System.currentTimeMillis());
            int index = random.nextInt(servers.size());
            
            for (int i = 0; i < servers.size(); i++) {
                String server = servers.get(index);
                try {
                    return callServer(api, params, body, server, method);
                } catch (NacosException e) {
                    exception = e;
                    if (NAMING_LOGGER.isDebugEnabled()) {
                        NAMING_LOGGER.debug("request {} failed.", server, e);
                    }
                }
                index = (index + 1) % servers.size();
            }
        }
        
        NAMING_LOGGER.error("request: {} failed, servers: {}, code: {}, msg: {}", api, servers, exception.getErrCode(),
                exception.getErrMsg());
        
        throw new NacosException(exception.getErrCode(),
                "failed to req API:" + api + " after all servers(" + servers + ") tried: " + exception.getMessage());
        
    }

二.服务端注册服务源码(2.0.2)

主要流程

服务端中有几个重要的类:Service、Client、ServiceManager、ClientManager.。
这几个类涉及管理服务的实体,注册服务接口,注销服务接口,心跳接口都是对这几个类进行操作。
ClientManager启动一个定时任务线程,对过期的服务进行清除

package com.alibaba.nacos.naming.controllers;



import static com.alibaba.nacos.naming.misc.UtilsAndCommons.DEFAULT_CLUSTER_NAME;

/**
 * Instance operation controller.
 *
 * @author nkorange
 */
@RestController
@RequestMapping(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_INSTANCE_CONTEXT)
public class InstanceController {
    
    @Autowired
    private SwitchDomain switchDomain;
    
    @Autowired
    private InstanceOperatorClientImpl instanceServiceV2;
    
    @Autowired
    private InstanceOperatorServiceImpl instanceServiceV1;
    
    @Autowired
    private UpgradeJudgement upgradeJudgement;
    
    /**
     * Register new instance.
     *
     * @param request http request
     * @return 'ok' if success
     * @throws Exception any error during register
     */
    @CanDistro
    @PostMapping
    @Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
    public String register(HttpServletRequest request) throws Exception {
        
        final String namespaceId = WebUtils
                .optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
        final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
        NamingUtils.checkServiceNameFormat(serviceName);
        //从request中获取实例信息z主要包括ip,port,服务名,group等信息
        final Instance instance = parseInstance(request);
		
        getInstanceOperator().registerInstance(namespaceId, serviceName, instance);
        return "ok";
    }
 }

	
	//这个方法是上面的getInstanceOperator().registerInstance(namespaceId, serviceName, instance)
    public void registerInstance(String namespaceId, String serviceName, Instance instance) {
        boolean ephemeral = instance.isEphemeral();
        //获取clientId(规则:ip:port#ephemeral 如192.168.9.145:8888#true)
        String clientId = IpPortBasedClient.getClientId(instance.toInetAddr(), ephemeral);
       //不存在该客户端则创建
        createIpPortClientIfAbsent(clientId, ephemeral);
        //创建一个service
        Service service = getService(namespaceId, serviceName, ephemeral);
        //注册实例
        clientOperationService.registerInstance(service, instance, clientId);
    }

	//下面是 clientOperationService.registerInstance(service, instance, clientId);
	//是EphemeralClientOperationServiceImpl实现类
    public void registerInstance(Service service, Instance instance, String clientId) {
        //如果service不存在则放到ServiceManager里,存在则返回存在的service(Service 重写了 equals方法)
        Service singleton = ServiceManager.getInstance().getSingleton(service);
        //从clientManager获取相应的client
        Client client = clientManager.getClient(clientId);
        //根据instance(前端参数) 构建InstancePublishInfo(要注册的实例 包含: ip、port、healthy、cluster)
        InstancePublishInfo instanceInfo = getPublishInfo(instance);
        //将服务实例添加到client
        client.addServiceInstance(singleton, instanceInfo);
        client.setLastUpdatedTime();
        //发布客户端注册事件
        NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
        NotifyCenter
                .publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));

	//EphemeralIpPortClientManager 是ClientManager实现类 是对临时的服务进行管理,naocs默认是临时服务 重点看一下清理服务的方法 默认没有心跳90s的服务会被清掉
   public EphemeralIpPortClientManager(DistroMapper distroMapper, SwitchDomain switchDomain) {
        this.distroMapper = distroMapper;
        //开启清除过期的客户端的线程 每5s执行一次
        GlobalExecutor.scheduleExpiredClientCleaner(new ExpiredClientCleaner(this, switchDomain), 0,
                Constants.DEFAULT_HEART_BEAT_INTERVAL, TimeUnit.MILLISECONDS);
        clientFactory = ClientFactoryHolder.getInstance().findClientFactory(ClientConstants.EPHEMERAL_IP_PORT);
    }
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值