Nacos-服务注册,服务发现(二)

Nacos健康检查

两种健康检查机制

Nacos作为注册中⼼, 需要感知服务的健康状态, 才能为服务调⽤⽅提供良好的服务。

Nacos 中提供了两种健康检查机制:

客⼾端主动上报机制:

  • 客⼾端通过⼼跳上报⽅式告知服务端(nacos注册中⼼)健康状态, 默认⼼跳间隔5秒;
  • nacos会在超过15秒未收到⼼跳后将实例设置为不健康状态, 超过30秒将实例删除

服务器端反向探测机制:

  • nacos主动探知客⼾端健康状态, 默认间隔为20秒.
  • 健康检查失败后实例会被标记为不健康, 不会被⽴即删除.

⽐如领导管理员⼯的⼯作

  1. 员⼯主动汇报: 员⼯每天主动汇报⾃⼰⼯作进度
  2. 领导主动问询: 领导每周向员⼯了解⼯作进度

Nacos 中的健康检查机制不能主动设置,健康检查机制是和 Nacos 的服务实例类型强相关的.

Nacos服务实例类型

Nacos的服务实例(注册的节点)分为临时实例和⾮临时实例.

临时实例

临时实例:如果实例宕机超过⼀定时间, 会从服务列表剔除, 默认类型.

⾮临时实例

⾮临时实例:如果实例宕机, 不会从服务列表剔除, 也可以叫永久实例

Nacos对临时实例, 采取的是 客⼾端主动上报机制, 对⾮临时实例, 采取服务器端反向探测机制

配置⼀个服务实例为永久实例

复制代码
spring:
  cloud:
    nacos:
      discovery:
        ephemeral: false # 设置为⾮临时实例

重启服务,观察nacos:

停止服务,再次观察nacos:

节点依然不会消失。

常⻅问题

1.Nacos服务实例类型不允许改变

设置服务实例类型, 重新启动Nacos可能会报错

报错信息参考:

复制代码
Caused by: com.alibaba.nacos.api.exception.NacosException: failed to req 
API:/nacos/v1/ns/instance after all servers([110.41.51.65:10020]) tried: 
caused: errCode: 400, errMsg: Current service DEFAULT_GROUP@@product-service is
 ephemeral service, can't register persistent instance. ;
 at 
com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy.reqApi(Naming
HttpClientProxy.java:410) ~[nacos-client-2.2.1.jar:na]
 at 
com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy.reqApi(Naming
HttpClientProxy.java:351) ~[nacos-client-2.2.1.jar:na]
 at 
com.alibaba.nacos.client.naming.remote.http.NamingHttpClientProxy.reqApi(Naming
HttpClientProxy.java:346) ~[nacos-client-2.2.1.jar:na]
//.......

原因: Nacos会记录每个服务实例的IP和端⼝号, 当发现IP和端⼝都没有发⽣变化时, Nacos不允许⼀个

服务实例类型发⽣变化, ⽐如从临时实例,变为⾮临时实例, 或者从⾮临时实例, 变成临时实例.

解决办法:

  1. 停掉nacos
  2. 删除nacos ⽬录下 /data/protocol/raft 信息, ⾥⾯会保存应⽤实例的元数据信息

2.服务正常, Nacos健康检查失败

原因和解决办法:

参考:如何解决Nacos持久化实例HTTP/TCP的健康检查不通过问题_微服务引擎(MSE)-阿里云帮助中心

Nacos环境隔离

企业开发中, ⼀个服务会分为开发环境, 测试环境和⽣产环境.

  1. 开发环境:开发⼈员⽤于开发的服务器, 是最基础的环境. ⼀般⽇志级别设置较低, 可能会开启⼀些调试信息.
  2. 测试环境:测试⼈员⽤来进⾏测试的服务器, 是开发环境到⽣产环境的过渡环境.
  3. ⽣产环境:正式提供对外服务的环境, 通常关掉调试信息.

通常情况下, 这⼏个环境是不能互相通信的. Nacos提供了namespace(命名空间)来实现环境的隔离. 不

同的namaspace的服务不可⻅

创建Namespace

默认情况下,所有服务都在同⼀个namespace,名为public

点击左侧命名空间, 就可以对namespace进⾏操作

新增命名空间

配置namespace

namespace创建完成后, 对服务进⾏配置

配置项 Key 默认值 说明
命名空间 spring.cloud.nacos.discovery.namespace 常⽤场景之⼀是不同环境的注册的区分隔离,
例如开发测试环境和⽣产环境的资源(如配置、服务)隔离等。

修改order-service的命名空间

复制代码
spring:
 cloud:
	 nacos:
		 discovery:
			 namespace: 8078d722-567c-4e27-9ff1-a42d6101a546  #(为命名空间ID)

测试远程调⽤

1. 启动服务, 观察Nacos控制台

public 命名空间下只有product-service服务(order-service 那个不用管,之前设置的是非临时实例,所以还在,但它的健康检查是为false,就不用管它)

order-service在dev命名空间下

2.访问接⼝, 测试远程调⽤

发现服务报错

复制代码
java.lang.IllegalStateException: No instances available for product-service
	at org.springframework.cloud.loadbalancer.blocking.client.BlockingLoadBalancerClient.execute(BlockingLoadBalancerClient.java:78) ~[spring-cloud-loadbalancer-4.0.3.jar:4.0.3]
	at org.springframework.cloud.client.loadbalancer.LoadBalancerInterceptor.intercept(LoadBalancerInterceptor.java:56) ~[spring-cloud-commons-4.0.3.jar:4.0.3]
	at org.springframework.http.client.InterceptingClientHttpRequest$InterceptingRequestExecution.execute(InterceptingClientHttpRequest.java:87) ~[spring-web-6.0.14.jar:6.0.14]
	at org.springframework.http.client.InterceptingClientHttpRequest.executeInternal(InterceptingClientHttpRequest.java:71) ~[spring-web-6.0.14.jar:6.0.14]
	at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48) ~[spring-web-6.0.14.jar:6.0.14]
	at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:66) ~[spring-web-6.0.14.jar:6.0.14]
	at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:862) ~[spring-web-6.0.14.jar:6.0.14]
	at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:764) ~[spring-web-6.0.14.jar:6.0.14]
	at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:378) ~[spring-web-6.0.14.jar:6.0.14]
	at com.reggie.order.service.OrderService.selectOrderById(OrderService.java:27) ~[classes/:na]
	at com.reggie.order.controller.OrderController.getOrderById(OrderController.java:19) ~[classes/:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
	........

3. 修改product-service的其中⼀个实例, 命名空间改为dev

复制代码
spring:
 cloud:
	 nacos:
		 discovery:
			 namespace: 8078d722-567c-4e27-9ff1-a42d6101a546  #(为命名空间ID)

4.启动服务

观察Nacos控制台

再次访问接⼝ 127.0.0.1:8080/order/1 , 发现远程调⽤成功

Nacos配置中⼼

除了注册中⼼和负载均衡之外, Nacos还是⼀个配置中⼼, 具备配置管理的功能.

Namespace 的常⽤场景之⼀是不同环境的配置区分隔离. 例如开发测试环境和⽣产环境的配置隔离.

为什么需要配置中⼼

当前项⽬的配置都在代码中, 会存在以下问题:

  1. 配置⽂件修改时, 服务需要重新部署. 微服务架构中, ⼀个服务可能有成百个实例, 挨个部署⽐较⿇

    烦, 且容易出错.

  2. 多⼈开发时, 配置⽂件可能需要经常修改, 使⽤同⼀个配置⽂件容易冲突.

配置中⼼就是对这些配置项进⾏统⼀管理. 通过配置中⼼, 可以集中查看, 修改和删除配置, ⽆需再逐个

修改配置⽂件. 提⾼效率的同时, 也降低了出错的⻛险.

  1. 服务启动时, 从配置中⼼读取配置项的内容, 进⾏初始化.
  2. 配置项修改时, 通知微服务, 实现配置的更新加载.

快速上⼿

通过以下操作, 我们先来感受下Nacos 配置中⼼的使⽤

参考⽂档:Nacos 融合 Spring Cloud,成为注册配置中心 | Nacos 官网

添加配置

在Nacos控制台添加配置项

<aside> 💡

注意: 配置管理的命名空间和服务列表的命名空间是隔离的, 两个是分别设置的. 默认是public,也就是服务管理命名空间配置 ≠ 配置管理的命名空间 ???没懂

</aside>

新建配置项

说明:

  1. Data ID 设置为项⽬名称
  2. 配置内容的数据格式, ⽬前只⽀持 properties 和 yaml 类型
  3. 设置配置内容

获取配置

  1. 引入 nacos config 依赖

    复制代码
         <dependency>
             <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
         </dependency>
         <!-- SpringCloud 2020.*之后版本需要引⼊bootstrap-->
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-bootstrap</artifactId>
         </dependency>
  2. 配置bootstrap.properties

微服务启动前, 需要先获取nacos中配置, 并与application.yml配置合并. 在微服务运⾏之前, Nacos要求 必须使⽤ bootstrap.properties 配置⽂件来配置Nacos Server 地址

复制代码
spring:
  application:
    name: product-service
	cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
  • spring.application.name 需要和nacos配置管理的Data ID⼀致
  • spring.cloud.nacos.config.server-addr 为Nacos Server的地址

<aside> 💡

配置中⼼和注册中⼼的配置是隔离的 Nacos 配置中⼼: spring.cloud.nacos.config.server-addr Nacos 注册中⼼: spring.cloud.nacos.discovery.server-addr

</aside>

  1. 编写程序

    复制代码
    @RefreshScope
    @RestController
    public class NacosConteoller {
    
        @Value("${nacos.test}")
        private String nacosConfig;
    
        @RequestMapping("/getConfig")
        public String getConfig(){
            return "从nacos获取配置项nacos.config:" + nacosConfig;
        }
    }
  • @Value 读取配置
  • @RefreshScope 配置进⾏热更新
  1. 测试

访问接口:127.0.0.1:9090/getConfig

在Nacos控制台修改 nacos.config

再次访问接口:

常⻅问题

  1. 读取不到配置项

    可能原因:

    1. 配置错误: 检查配置Data ID, 配置格式, 配置空间等
    2. 未引⼊依赖
  2. No spring.config.import property has been defined

    启动报错⽇志:

    复制代码
    ***************************
    APPLICATION FAILED TO START
    ***************************
    Description:
    No spring.config.import property has been defined
    Action:
    Add a spring.config.import=nacos: property to your configuration.
     If configuration is not required add 
    spring.config.import=optional:nacos: instead.
     To disable this check, set spring.cloud.nacos.config.importcheck.enabled=false.

    原因: bootstrap.properties 是系统级的资源配置⽂件, ⽤于程序执⾏更加早期配置信息读

    取. 但是SpringCloud 2020.* 之后的版本把bootstrap禁⽤了, 导致在读取⽂件的时候读取不到⽽报

    错, 所以需要重新导⼊bootstrap 包进来就可以了

  3. Nacos Server地址配置错误

    报错信息如下:

    复制代码
    2023-12-28T17:12:53.070+08:00 ERROR 14356 --- [t.remote.worker] 
    c.a.n.c.remote.client.grpc.GrpcClient : Server check fail, please check 
    server 127.0.0.1 ,port 11020 is available , error ={}
    java.util.concurrent.ExecutionException: 
    com.alibaba.nacos.shaded.io.grpc.StatusRuntimeException: UNAVAILABLE: io
    exception
     at 
    com.alibaba.nacos.shaded.com.google.common.util.concurrent.AbstractFuture.ge
    tDoneValue(AbstractFuture.java:566) ~[nacos-client-2.2.1.jar:na]
     at 
    com.alibaba.nacos.shaded.com.google.common.util.concurrent.AbstractFuture.ge
    t(AbstractFuture.java:445) ~[nacos-client-2.2.1.jar:na]
    // ...
     
    Caused by: com.alibaba.nacos.shaded.io.grpc.StatusRuntimeException:
    UNAVAILABLE: io exception
     at 
    com.alibaba.nacos.shaded.io.grpc.Status.asRuntimeException(Status.java:539) 
    ~[nacos-client-2.2.1.jar:na]
     at 
    com.alibaba.nacos.shaded.io.grpc.stub.ClientCalls$UnaryStreamToFuture.onClos
    e(ClientCalls.java:544) ~[nacos-client-2.2.1.jar:na]
     at 
    com.alibaba.nacos.shaded.io.grpc.internal.DelayedClientCall$DelayedListener$
    3.run(DelayedClientCall.java:471) ~[nacos-client-2.2.1.jar:na]
     // ...
    Caused by: 
    com.alibaba.nacos.shaded.io.grpc.netty.shaded.io.netty.channel.AbstractChann
    el$AnnotatedConnectException: Connection refused: no further information: 
    /127.0.0.1:11020
    Caused by: java.net.ConnectException: Connection refused: no further
    information
     at java.base/sun.nio.ch.Net.pollConnect(Native Method) ~[na:na]
     at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:672) ~[na:na]
     at 
    java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:
    946) ~[na:na]

配置中⼼详解

设置命名空间

Nacos配置管理的命名空间和服务列表的命名空间是分别设置的. 默认是public

Nacos命名空间配置依然在bootstrap.yml中进⾏配置

复制代码
spring:
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        namespace: 8078d722-567c-4e27-9ff1-a42d6101a546   #配置中心的命名空间

如果设置命名空间后, 项⽬启动时, 会从该命名空间下找对应的配置项:

再次访问接口:127.0.0.1:9090/getConfig

Data Id

Data Id 格式介绍

在 Nacos Spring Cloud 中, dataId 的完整格式如下:

复制代码
${prefix}-${spring.profiles.active}.${file-extension}
  • prefix 默认为 spring.application.name 的值, 也可以通过配置项spring.cloud.nacos.config.prefix 来配置.
  • spring.profiles.active 即为当前环境对应的 profile. 当 spring.profiles.active为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 {prefix}.{fileextension}
  • file-exetension 为配置内容的数据格式,可以通过配置项spring.cloud.nacos.config.file-extension 来配置。⽬前只⽀持 properties和 yaml 类型. 默认为properties.

微服务启动时, 会从Nacos读取多个配置⽂件:

  1. {prefix}-{spring.profiles.active}.${file-extension} 如: product-service-dev.properties
  2. {prefix}.{file-extension} , 如: product-service.properties
  3. ${prefix} 如product-service

<aside> 💡

{[spring.application.name](http://spring.application.name/ "spring.application.name")}, {spring.profiles.active} 等通过配置⽂件来指定时, 必须放在 bootstrap.properties ⽂件中

</aside>

三个⽂件的优先级为: product-service-dev.properties > product-service.properties > productservice

观察⽇志

在bootstrap.yml中添加 spring.profiles.active 值

复制代码
spring:
	 profiles:
		 active: dev

    #pom.xml
    <profiles>
        <profile>
            <id>dev</id>
            <properties>
                <profile.name>dev</profile.name>
            </properties>
        </profile>
        <profile>
            <id>prod</id>
            <properties>
                <profile.name>prod</profile.name>
            </properties>
        </profile>
    </profiles>

启动服务, 观察⽇志

复制代码
2023-12-28T18:48:08.614+08:00 INFO 36672 --- [ main] 
c.a.n.client.config.impl.ClientWorker : [fixed-51152a13-7911-49e3-bbdc-
16fd5670a257-110.41.51.65_10020] [subscribe] product-servicedev.properties+DEFAULT_GROUP+51152a13-7911-49e3-bbdc-16fd5670a257
2023-12-28T18:48:08.624+08:00 INFO 36672 --- [ main] 
c.a.nacos.client.config.impl.CacheData : [fixed-51152a13-7911-49e3-bbdc-
16fd5670a257-110.41.51.65_10020] [**add-listener**] ok, tenant=51152a13-7911-49e3-
bbdc-16fd5670a257, **dataId=product-service-dev.properties**, group=DEFAULT_GROUP, 
cnt=1
2023-12-28T18:48:08.624+08:00 INFO 36672 --- [ main] 
c.a.c.n.refresh.NacosContextRefresher : [Nacos Config] Listening config: 
dataId=product-service-dev.properties, group=DEFAULT_GROUP
2023-12-28T18:48:08.625+08:00 INFO 36672 --- [ main] 
c.a.n.client.config.impl.ClientWorker : [fixed-51152a13-7911-49e3-bbdc-
16fd5670a257-110.41.51.65_10020] [subscribe] productservice.properties+DEFAULT_GROUP+51152a13-7911-49e3-bbdc-16fd5670a257
2023-12-28T18:48:08.625+08:00 INFO 36672 --- [ main] 
c.a.nacos.client.config.impl.CacheData : [fixed-51152a13-7911-49e3-bbdc-
16fd5670a257-110.41.51.65_10020] [**add-listener**] ok, tenant=51152a13-7911-49e3-
bbdc-16fd5670a257, **dataId=product-service.properties**, group=DEFAULT_GROUP, 
cnt=1
2023-12-28T18:48:08.625+08:00 INFO 36672 --- [ main] 
c.a.c.n.refresh.NacosContextRefresher : [Nacos Config] Listening config: 
dataId=product-service.properties, group=DEFAULT_GROUP
2023-12-28T18:48:08.626+08:00 INFO 36672 --- [ main] 
c.a.n.client.config.impl.ClientWorker : [fixed-51152a13-7911-49e3-bbdc-
16fd5670a257-110.41.51.65_10020] [subscribe] productservice+DEFAULT_GROUP+51152a13-7911-49e3-bbdc-16fd5670a257
2023-12-28T18:48:08.627+08:00 INFO 36672 --- [ main] 
c.a.nacos.client.config.impl.CacheData : [fixed-51152a13-7911-49e3-bbdc-
16fd5670a257-110.41.51.65_10020] [**add-listener**] ok, tenant=51152a13-7911-49e3-
bbdc-16fd5670a257, **dataId=product-service**, group=DEFAULT_GROUP, cnt=1
2023-12-28T18:48:08.627+08:00 INFO 36672 --- [ main] 
c.a.c.n.refresh.NacosContextRefresher : [Nacos Config] Listening config: 
dataId=product-service, group=DEFAULT_GROUP

测试

bootstrap.yml配置如下:

复制代码
spring:
  application:
    name: product-service
  profiles:
    active: @profile.name@
  cloud:
    nacos:
      config:
        server-addr: 127.0.0.1:8848
        namespace: 8078d722-567c-4e27-9ff1-a42d6101a546   #配置中心的命名空间

配置项如下:

访问接⼝: http://127.0.0.1:9090/getConfig

服务获取到了 product-service-dev.properties 的值

删除 product-service-dev.properties 配置, 再次访问接⼝

<aside> 💡

注意:

  1. bootstrap.yml 设置的配置格式必须和nacos控制台配置的数据格式保持⼀致.
  2. 不设置配置格式(spring.cloud.nacos.config.file-extension)时, 默认为properties </aside>

Nacos与Eureka的区别

共同点:

  • 都⽀持服务注册和服务拉取

区别:

  1. 功能

    Nacos除了服务发现和注册之外, 还提供了配置中⼼, 流量管理和DNS服务等功能.

  2. CAP理论

    Eureka遵循AP原则, Nacos可以切换AP和CP模式,默认AP.

    Nacos 根据配置识别CP或者AP模式. 如果注册Nacos的Client的节点是临时节点, 那么Nacos对这个

    Client节点的效果就是AP, 反之是CP. AP和CP可以同时混合存在.

  3. 服务发现

    Eureka:基于拉模式. Eureka Client会定期从Server拉取服务信息, 有缓存, 默认每30秒拉取⼀次.

    Nacos:基于推送模式. 服务列表有变化时实时推送给订阅者, 服务端和客⼾端保持⼼跳连接.

相关推荐
MengFly_3 天前
Java广播 —如何利用广播做服务发现
java·网络·服务发现
rchmin6 天前
Nacos服务与配置管理平台介绍
架构·服务发现·配置管理
oMcLin9 天前
如何在 CentOS 7.9 上配置并调优 Docker Swarm 集群,确保跨多个节点的高效服务发现与负载均衡?
docker·centos·服务发现
喵叔哟10 天前
19.服务集成与通信
后端·docker·容器·服务发现
喵叔哟16 天前
15.故障排查与调试
后端·docker·容器·服务发现
没有bug.的程序员22 天前
Spring Cloud Gateway 架构与执行流程:从原理到性能优化的深度探索
微服务·云原生·eureka·性能优化·架构·sentinel·服务发现
没有bug.的程序员25 天前
Sentinel 流控原理深度解析:从SlotChain到热点参数限流的设计哲学
jvm·微服务·云原生·eureka·sentinel·服务发现
运维开发小白25 天前
服务发现中间件ConSul的操作指南
中间件·服务发现·consul
没有bug.的程序员1 个月前
Nacos vs Eureka 服务发现深度对比
jvm·微服务·云原生·容器·eureka·服务发现