04 业务服务注册到 nacos 默认权重为0, 导致 gateway 获取不到业务服务

Posted 蓝风9

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了04 业务服务注册到 nacos 默认权重为0, 导致 gateway 获取不到业务服务相关的知识,希望对你有一定的参考价值。

前言

最近搭建 xxx服务 的时候碰到了一个这样的问题 

某业务服务 启动之后, 注册到 nacos, 然后 从 gateway 来获取该服务却报错, 没有找到 xxx服务 

之前 记录了一个 todo, 今天 来梳理一下 

主要是会涉及到我们关注的问题, 以及 服务的注册流程 不会大而全 

nacos 服务实例元数据存储在哪里?

根据服务查询 服务实例 的接口为 "/v1/ns/catalog/instances", 处理的方法入口为 CatalogController.instanceList 

里面查询 服务实例 主要是 ServiceStorage.serviceDataIndexes, 根据 service 获取到 实例列表 

所以 在服务注册的流程中会将 当前服务实例 注册到 nacos 的 ServiceStorage.serviceDataIndexes 中 

nacos 服务注册流程

主要有两个方面, 一个方面是 客户端 请求服务注册, 另一方面是 nacos 服务器对于 服务注册请求 的处理 

客户端 请求服务注册, 主要是在 上下文 初始化完成之后发布了事件, 然后 NacosAutoServiceRegistration 里面开始向 nacos 注册 

nacos 服务器对于 服务注册请求 的处理, 这里可以抽象的理解为 将实例注册到 ServiceStorage.serviceDataIndexes, 其他的细节在我们这里的问题中, 我们并不关注 

客户端请求服务注册

客户端 请求服务注册 的堆栈信息如下 

在 上下文 初始化完成之后发布了事件, 然后 NacosAutoServiceRegistration 里面开始向 nacos 注册 

请求的 url 为 "http://10.60.50.16:8849/nacos/v1/ns/instance

携带的参数来自于 当前服务的上下文, 以及 nacosDiscoveryProperties 

nacosDiscoveryProperties 读取自 spring.cloud.nacos.discovery 的相关配置 

request:86, HttpClient (com.alibaba.nacos.client.naming.net)
callServer:433, NamingProxy (com.alibaba.nacos.client.naming.net)
reqAPI:468, NamingProxy (com.alibaba.nacos.client.naming.net)
reqAPI:401, NamingProxy (com.alibaba.nacos.client.naming.net)
reqAPI:397, NamingProxy (com.alibaba.nacos.client.naming.net)
registerService:212, NamingProxy (com.alibaba.nacos.client.naming.net)
registerInstance:207, NacosNamingService (com.alibaba.nacos.client.naming)
registerInstance:187, NacosNamingService (com.alibaba.nacos.client.naming)
register:63, NacosServiceRegistry (org.springframework.cloud.alibaba.nacos.registry)
register:239, AbstractAutoServiceRegistration (org.springframework.cloud.client.serviceregistry)
register:74, NacosAutoServiceRegistration (org.springframework.cloud.alibaba.nacos.registry)
start:138, AbstractAutoServiceRegistration (org.springframework.cloud.client.serviceregistry)
bind:101, AbstractAutoServiceRegistration (org.springframework.cloud.client.serviceregistry)
onApplicationEvent:88, AbstractAutoServiceRegistration (org.springframework.cloud.client.serviceregistry)
onApplicationEvent:47, AbstractAutoServiceRegistration (org.springframework.cloud.client.serviceregistry)
doInvokeListener:172, SimpleApplicationEventMulticaster (org.springframework.context.event)
invokeListener:165, SimpleApplicationEventMulticaster (org.springframework.context.event)
multicastEvent:139, SimpleApplicationEventMulticaster (org.springframework.context.event)
publishEvent:402, AbstractApplicationContext (org.springframework.context.support)
publishEvent:359, AbstractApplicationContext (org.springframework.context.support)
finishRefresh:165, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:552, AbstractApplicationContext (org.springframework.context.support)
refresh:141, ServletWebServerApplicationContext (org.springframework.boot.web.servlet.context)
refresh:743, SpringApplication (org.springframework.boot)
refreshContext:390, SpringApplication (org.springframework.boot)
run:312, SpringApplication (org.springframework.boot)
run:1214, SpringApplication (org.springframework.boot)
run:1203, SpringApplication (org.springframework.boot)

nacos 服务器对于 服务注册请求 的处理

nacos 服务器这边 处理的堆栈信息如下 

ServiceStorage 中主要包含了 clientManager, serviceIndexesManager, serviceDataIndexes, serviceClusterIndex 这几个数据结构, 在服务注册的流程中都会填充对应的数据 

主要的处理有 注册 service → client + InstancePublishInfo 到 ServiceStorage.clientManager 

封装 ClientOperationEvent.ClientRegisterServiceEvent 事件发布, 这个事件会关联到后面的一系列的业务处理 

registerInstance:65, EphemeralClientOperationServiceImpl (com.alibaba.nacos.naming.core.v2.service.impl)
registerInstance:50, ClientOperationServiceProxy (com.alibaba.nacos.naming.core.v2.service)
registerInstance:104, InstanceOperatorClientImpl (com.alibaba.nacos.naming.core)
register:115, InstanceController (com.alibaba.nacos.naming.controllers)

ClientRegisterServiceEvent  的处理会涉及到如下业务流程, 一个事件链 

ClientRegisterServiceEvent -> ServiceChangedEvent -> PushDelayTaskExecuteEngine -> PushExecuteTask.run

ClientRegisterServiceEvent 的事件处理, 会注册 service -> clientId 到 ServiceStorage.serviceIndexesManager 中


PushExecuteTask.run 里面涉及的处理主要是刷新 ServiceStorage.serviceDataIndexes, serviceClusterIndex
主要的处理是在 ServiceStorage.getPushData 中, 处理之后 当前服务的所有 Instance 列表就更新了
也就是上面提到的 "将实例注册到 ServiceStorage.serviceDataIndexes"

parseInstance:128, ServiceStorage (com.alibaba.nacos.naming.core.v2.index)
getAllInstancesFromIndex:109, ServiceStorage (com.alibaba.nacos.naming.core.v2.index)
getPushData:84, ServiceStorage (com.alibaba.nacos.naming.core.v2.index)
generatePushData:76, PushExecuteTask (com.alibaba.nacos.naming.push.v2.task)
run:58, PushExecuteTask (com.alibaba.nacos.naming.push.v2.task)
run:116, TaskExecuteWorker$InnerWorker (com.alibaba.nacos.common.task.engine)

为什么 xxx服务 注册到 nacos 之后默认权重为 0?

在 nacos 中 Instance 的默认 weight 为 1 

但是 为什么 xxx服务 注册到 nacos 之后 默认权重为 0 呢?

nacos 这边 InstanceController.register 拿到的 Instance 的权重为 0, 原因是客户端传过来的 weight 参数值为 0 

进而 注册到 clientManager 的 InstancePublishInfo 中的 weight 为 0 

ServiceStorage.getPushData 中获取 服务的所有 Instnace 的时候, 从 clientManager 中拿到的 InstancePublishInfo 的 weight 为 0 

进而 导致了 ServiceStorage.serviceDataIndexes 的服务对应的 Instnace 的 weight 为 0 

app -> unknown
metadata -> "instance":"DESKTOP-SphpNQ2","preserved.register.source":"SPRING_CLOUD","uptime":"2022-03-02 16:02:27"
ip -> 10.60.50.16
weight -> 0.0
ephemeral -> true
encoding -> UTF-8
groupName -> DEFAULT_GROUP
namespaceId -> xxx_config
port -> 7703
enable -> true
healthy -> true

客户端发送 服务注册请求 的时候 

携带的参数来自于 当前服务的上下文, 以及 nacosDiscoveryProperties, 我们这里关注的权重来自于 nacosDiscoveryProperties.weight 

查看一下 xxx服务 这边的 spring.cloud.nacos.discovery.weight 的配置, 写死的 0 

            String serviceId = registration.getServiceId();
            Instance instance = new Instance();
            instance.setIp(registration.getHost());
            instance.setPort(registration.getPort());
            instance.setWeight((double)this.nacosDiscoveryProperties.getWeight());
            instance.setClusterName(this.nacosDiscoveryProperties.getClusterName());
            instance.setMetadata(registration.getMetadata());

            try 
                this.namingService.registerInstance(serviceId, instance);
                log.info("nacos registry,  : register finished", new Object[]serviceId, instance.getIp(), instance.getPort());
             catch (Exception var5) 
                log.error("nacos registry,  register failed...,", new Object[]serviceId, registration.toString(), var5);
            

gateway 这边获取 xxx服务实例 的时候过滤掉 weight 小于等于 0 的处理 

具体的处理是在 NacosNamingService.selectInstances(ServiceInfo serviceInfo, boolean healthy) 中 

    private List<Instance> selectInstances(ServiceInfo serviceInfo, boolean healthy) 
        List list;
        if (serviceInfo != null && !CollectionUtils.isEmpty(list = serviceInfo.getHosts())) 
            Iterator iterator = list.iterator();

            while(true) 
                Instance instance;
                do 
                    if (!iterator.hasNext()) 
                        return list;
                    

                    instance = (Instance)iterator.next();
                 while(healthy == instance.isHealthy() && instance.isEnabled() && instance.getWeight() > 0.0D);

                iterator.remove();
            
         else 
            return new ArrayList();
        
    

完 

以上是关于04 业务服务注册到 nacos 默认权重为0, 导致 gateway 获取不到业务服务的主要内容,如果未能解决你的问题,请参考以下文章

SpringCloud Nacos 注册中心 -- 服务实例的权重设置(根据权重负载均衡)环境隔离(命名空间namespace)Nacos(细节分析)和Eureka的对比临时/非临时实例

如何平滑将注册中心从Eureka迁移到Nacos?

SpringBoot使用Nacos进行服务注册发现与配置管理

Nacos使用快速入门

※Spring全家桶从入门到X神--快学阿里巴巴的Nacos注册中心

从0开始学微服务 --- 2020年04月