spring cloud nacos 集成服务注册和发现,配置管理

2022年7月16日 437点热度 0人点赞 0条评论

本示例是基于spring-boot-2.6.3、windows10、nacos-server-2.1.0的环境下进行研究记录。

对于一些版本的区别,还请自行去查阅。尤其是spring-cloud和spring-cloud-alibaba的版本对应。

项目依赖


<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.6.3</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
    <java.version>1.8</java.version>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <spring-cloud-dependencies.version>2021.0.3</spring-cloud-dependencies.version>
    <spring-cloud-alibaba-dependencies.version>2021.0.1.0</spring-cloud-alibaba-dependencies.version>
    <spring-boot.version>2.6.3</spring-boot.version>
</properties>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <!--服务注册发现和注册-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!--配置中心依赖-->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
    </dependency>
    <!--解决引入bootstrap.yml不生效问题-->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-bootstrap</artifactId>
    </dependency>
</dependencies>
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>${spring-boot.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <!--版本对应 https://start.spring.io/actuator/info-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud-dependencies.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-dependencies</artifactId>
            <version>${spring-cloud-alibaba-dependencies.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

到此,我们基于spring-cloud的项目依赖就完成了。我们创建一个名为micro-svc-provider的boot项目,引入上述配置,并以test环境为例展开。

接下来,我们在nacos-server中增加一个配置micro-svc-provider-test.yaml配置,为啥名字是这样,可否是别的名字,这个后面[注释1]会逐步介绍。

配置管理

我们先来看一下效果,再一个个展开描述。

图片

配置内容为yaml格式的信息

图片

代码配置

在bootstrap.yml中配置如下


server:
  port: 8081
logging:
  level:
    root: info
spring:
  application:
    name: micro-svc-provider
  profiles:
    active: test

并且,通过bootstrap.yml配置了服务注册和配置中心相关信息。可能你会问,为啥在bootstrap-test.yml中配置,而不是application-test.yml中配置。其实这跟配置加载顺序有关系,这里引用网上一段描述:

bootstrap.yml(bootstrap.properties)与application.yml(application.properties)执行顺序

  • bootstrap.yml(bootstrap.properties)用来程序引导时执行,应用于更加早期配置信息读取,如可以使用来配置application.yml中使用到参数等

  • application.yml(application.properties) 应用程序特有配置信息,可以用来配置后续各个模块中需使用的公共参数等。

加载顺序 bootstrap.yml > application.yml > application-{spring.profiles.active}.yml

所以,bootstrap.yaml更多的是配置一些不经常变化甚至不变化的属性。application.yaml属性文件可更灵活的配置一些属性。

在spring-cloud官方文档中,也有对于bootstrap和application的一段描述:

官网文档地址:https://cloud.spring.io/spring-cloud-static/Dalston.SR5/single/spring-cloud.html#_the_bootstrap_application_context

 

图片

在bootstrap-test.yml中配置如下


# test环境
spring:
  cloud:
    nacos:
      discovery: # 服务注册发现相关配置
        server-addr: localhost:8848 # IP and port of the Nacos Server listener
        service: ${spring.application.name} # Name the current service,default spring.application.name
        group: DEFAULT_GROUP
        heart-beat-interval: 5000
        heart-beat-timeout: 15000
        ip-delete-timeout: 30000
        watch-delay: 10000
        namespace: 59bf057a-84c7-48ca-88e0-9f4fdc14a098 # 不配置,可能注册不成功
        enabled: true
        username: nacos
        password: nacos
      config: # 配置中心相关配置
        server-addr: localhost:8848
        file-extension: yaml # 目前支持yaml、properties两种,其他不支持
        group: DEFAULT_GROUP # 如果是默认group,这里可以不用配置,否则是必须得配置的
        namespace: 59bf057a-84c7-48ca-88e0-9f4fdc14a098 # 不配置,可能加载不到配置
        username: nacos
        password: nacos

因为配置中心的data-id为micro-svc-provider-test.yaml,所以这里指定了file-extension: yaml,并且还要指定namespace,否则配置中心信息可能读取不到。

:: Spring Boot ::                (v2.6.3)
2022-07-15 11:26:37.907  WARN 25156 --- [           main] c.a.c.n.c.NacosPropertySourceBuilder     : Ignore the empty nacos configuration and get it based on dataId[micro-svc-provider] & group[DEFAULT_GROUP]
2022-07-15 11:26:37.910  WARN 25156 --- [           main] c.a.c.n.c.NacosPropertySourceBuilder     : Ignore the empty nacos configuration and get it based on dataId[micro-svc-provider.yaml] & group[DEFAULT_GROUP]
2022-07-15 11:26:37.919  INFO 25156 --- [           main] b.c.PropertySourceBootstrapConfiguration : Located property source: [BootstrapPropertySource {name='bootstrapProperties-micro-svc-provider-test.yaml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-micro-svc-provider.yaml,DEFAULT_GROUP'}, BootstrapPropertySource {name='bootstrapProperties-micro-svc-provider,DEFAULT_GROUP'}]
2022-07-15 11:26:37.929  INFO 25156 --- [           main] c.e.m.MicroSvcProviderApplication        : The following profiles are active: test
2022-07-15 11:26:38.328  INFO 25156 --- [           main] o.s.cloud.context.scope.GenericScope     : BeanFactory id=9401bf5b-87c7-3ba8-99c9-b48c8864a8e6
2022-07-15 11:26:38.555  INFO 25156 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port(s): 8081 (http)
2022-07-15 11:26:40.566  INFO 25156 --- [           main] com.alibaba.nacos.client.naming          : [BEAT] adding beat: BeatInfo{port=8081, ip='172.30.0.1', weight=1.0, serviceName='DEFAULT_GROUP@@micro-svc-provider', cluster='DEFAULT', metadata={preserved.heart.beat.timeout=15000, preserved.ip.delete.timeout=30000, preserved.register.source=SPRING_CLOUD, preserved.heart.beat.interval=5000}, scheduled=false, period=5000, stopped=false} to beat map.
2022-07-15 11:26:40.566  INFO 25156 --- [           main] com.alibaba.nacos.client.naming          : [REGISTER-SERVICE] 59bf057a-84c7-48ca-88e0-9f4fdc14a098 registering service DEFAULT_GROUP@@micro-svc-provider with instance: Instance{instanceId='null', ip='172.30.0.1', port=8081, weight=1.0, healthy=true, enabled=true, ephemeral=true, clusterName='DEFAULT', serviceName='null', metadata={preserved.heart.beat.timeout=15000, preserved.ip.delete.timeout=30000, preserved.register.source=SPRING_CLOUD, preserved.heart.beat.interval=5000}}
2022-07-15 11:26:40.569  INFO 25156 --- [           main] c.a.c.n.registry.NacosServiceRegistry    : nacos registry, DEFAULT_GROUP micro-svc-provider 172.30.0.1:8081 register finished
2022-07-15 11:26:40.945  INFO 25156 --- [g.push.receiver] com.alibaba.nacos.client.naming          : received push data: {"type":"dom","data":"{\"name\":\"DEFAULT_GROUP@@micro-svc-provider\",\"clusters\":\"DEFAULT\",\"cacheMillis\":10000,\"hosts\":[{\"instanceId\":\"172.30.0.1#8081#DEFAULT#DEFAULT_GROUP@@micro-svc-provider\",\"ip\":\"172.30.0.1\",\"port\":8081,\"weight\":1.0,\"healthy\":true,\"enabled\":true,\"ephemeral\":true,\"clusterName\":\"DEFAULT\",\"serviceName\":\"DEFAULT_GROUP@@micro-svc-provider\",\"metadata\":{\"preserved.heart.beat.timeout\":\"15000\",\"preserved.ip.delete.timeout\":\"30000\",\"preserved.register.source\":\"SPRING_CLOUD\",\"preserved.heart.beat.interval\":\"5000\"},\"instanceHeartBeatInterval\":5000,\"instanceHeartBeatTimeOut\":15000,\"ipDeleteTimeout\":30000}],\"lastRefTime\":1657855600944,\"checksum\":\"\",\"allIPs\":false,\"reachProtectionThreshold\":false,\"valid\":true}","lastRefTime":146987339679400} from /172.30.0.1
2022-07-15 11:26:40.961  INFO 25156 --- [g.push.receiver] com.alibaba.nacos.client.naming          : new ips(1) service: DEFAULT_GROUP@@micro-svc-provider@@DEFAULT -> [{"instanceId":"172.30.0.1#8081#DEFAULT#DEFAULT_GROUP@@micro-svc-provider","ip":"172.30.0.1","port":8081,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"DEFAULT","serviceName":"DEFAULT_GROUP@@micro-svc-provider","metadata":{"preserved.heart.beat.timeout":"15000","preserved.ip.delete.timeout":"30000","preserved.register.source":"SPRING_CLOUD","preserved.heart.beat.interval":"5000"},"ipDeleteTimeout":30000,"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000}]
2022-07-15 11:26:40.966  INFO 25156 --- [g.push.receiver] com.alibaba.nacos.client.naming          : current ips:(1) service: DEFAULT_GROUP@@micro-svc-provider@@DEFAULT -> [{"instanceId":"172.30.0.1#8081#DEFAULT#DEFAULT_GROUP@@micro-svc-provider","ip":"172.30.0.1","port":8081,"weight":1.0,"healthy":true,"enabled":true,"ephemeral":true,"clusterName":"DEFAULT","serviceName":"DEFAULT_GROUP@@micro-svc-provider","metadata":{"preserved.heart.beat.timeout":"15000","preserved.ip.delete.timeout":"30000","preserved.register.source":"SPRING_CLOUD","preserved.heart.beat.interval":"5000"},"ipDeleteTimeout":30000,"instanceHeartBeatInterval":5000,"instanceHeartBeatTimeOut":15000}]
2022-07-15 11:26:41.211  INFO 25156 --- [           main] c.e.m.MicroSvcProviderApplication        : Started MicroSvcProviderApplication in 5.414 seconds (JVM running for 6.635)
2022-07-15 11:26:41.215  INFO 25156 --- [           main] c.a.n.client.config.impl.ClientWorker    : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [subscribe] micro-svc-provider.yaml+DEFAULT_GROUP+59bf057a-84c7-48ca-88e0-9f4fdc14a098
2022-07-15 11:26:41.215  INFO 25156 --- [           main] c.a.nacos.client.config.impl.CacheData   : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider.yaml, group=DEFAULT_GROUP, cnt=1
2022-07-15 11:26:41.216  INFO 25156 --- [           main] c.a.c.n.refresh.NacosContextRefresher    : listening config: dataId=micro-svc-provider.yaml, group=DEFAULT_GROUP
2022-07-15 11:26:41.217  INFO 25156 --- [           main] c.a.n.client.config.impl.ClientWorker    : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [subscribe] micro-svc-provider-test.yaml+DEFAULT_GROUP+59bf057a-84c7-48ca-88e0-9f4fdc14a098
2022-07-15 11:26:41.217  INFO 25156 --- [           main] c.a.nacos.client.config.impl.CacheData   : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider-test.yaml, group=DEFAULT_GROUP, cnt=1
2022-07-15 11:26:41.218  INFO 25156 --- [           main] c.a.c.n.refresh.NacosContextRefresher    : listening config: dataId=micro-svc-provider-test.yaml, group=DEFAULT_GROUP
2022-07-15 11:26:41.218  INFO 25156 --- [           main] c.a.n.client.config.impl.ClientWorker    : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [subscribe] micro-svc-provider+DEFAULT_GROUP+59bf057a-84c7-48ca-88e0-9f4fdc14a098
2022-07-15 11:26:41.218  INFO 25156 --- [           main] c.a.nacos.client.config.impl.CacheData   : [fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider, group=DEFAULT_GROUP, cnt=1
2022-07-15 11:26:41.218  INFO 25156 --- [           main] c.a.c.n.refresh.NacosContextRefresher    : listening config: dataId=micro-svc-provider, group=DEFAULT_GROUP
2022-07-15 11:27:26.577  INFO 25156 --- [nio-8081-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2022-07-15 11:27:26.577  INFO 25156 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2022-07-15 11:27:26.578  INFO 25156 --- [nio-8081-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 1 ms

从以上输出日志中可以看出,在启动时,对于配置中心,会有三种名称的配置加载,这也就解释了上述提到了[注释1]命名可以是哪些。具体三种名字如下:

  • 1、micro-svc-provider-${spring.profiles.active}.yaml

[fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider-test.yaml, group=DEFAULT_GROUP, cnt=1

监测配置变化 listening config: dataId=micro-svc-provider-test.yaml, group=DEFAULT_GROUP

  • 2、micro-svc-provider

[fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider, group=DEFAULT_GROUP, cnt=1

监测配置变化 listening config: dataId=micro-svc-provider, group=DEFAULT_GROUP

  • 3、micro-svc-provider.yaml

[fixed-localhost_8848-59bf057a-84c7-48ca-88e0-9f4fdc14a098] [add-listener] ok, tenant=59bf057a-84c7-48ca-88e0-9f4fdc14a098, dataId=micro-svc-provider.yaml, group=DEFAULT_GROUP, cnt=1

监测配置变化 listening config: dataId=micro-svc-provider.yaml, group=DEFAULT_GROUP

所以,在配置时,需要注意哪些配置放在哪里合适。否则多个配置文件生效造成配置干扰,排查起来会很崩溃。

在application-test.yml中配置

这里可以配置跟业务相关的配置,有别于bootstrap.yml中的配置信息。比如


# 自定义其他信息
env: test-application-provider

 

来个栗子


@RefreshScope // 使得配置更新生效,也是cloud中的功能
@RestController
public class EchoController {
    @Value(value = "${msg:null}") // 这里需要注意的是需要给默认值,否则启动时报错
    private String msg;
    @Value("${env:null}") // 这里需要注意的是需要给默认值,否则启动时报错
    private String env;
    @GetMapping(value = "/echo/{string}")
    public String echo(@PathVariable String string) {
        return env + ":" + msg + " from micro-svc-provider " + string;
    }
}

这里涉及到两个点需要提一下:

1、@RefreshScope :使得配置更新生效,也是cloud中的功能

2、@Value("${env:null}") :这里需要注意的是需要给默认值,否则启动时报错,这里用来测试application-test.yml中的配置是否生效用的。而@Value(value = "${msg:null}")是测试nacos配置是否生效用的。

 

运行

将项目运行起来后,通过访问 http://localhost:8081/echo/ssss,正常情况下,会输出:

test-application-provider:from-micro-svc-provider-test.yaml-modified from micro-svc-provider ssss

其中,test-application-provider 来自于application-test.yml配置

from-micro-svc-provider-test.yaml-modified:来自于nacos配置中心

 

到此,我们基于配置中心的配置读取就完成,对于配置更新和实时更新可以自行测试。因为配置了@RefreshScope,所以更新会即时同步的。

 

服务注册发现

上面,简单介绍了服务配置相关的设置和项目集成。接下来我们继续下一部分功能,即服务注册和发现。

仔细阅读的朋友应该发现了,上面在bootstrap-test.yml中已经配置了出config之外的discovery的配置节点。这个节点就是服务注册发现相关的配置。是不是也挺简单的。

图片

《服务管理-提供方》

配置完discovery节点,项目运行起来后,就可以在服务管理-服务列表内看到服务信息了。

图片

这里涉及到一些保护阈值、服务的心跳时间等等配置,具体一些细节可以参考官方文档研读。也可以翻阅源码com.alibaba.cloud.nacos.NacosDiscoveryProperties,可以看到很多属性serverAddr, username, password, endpoint, namespace, watchDelay, logName, service, weight, clusterName, group, namingLoadCacheAtStart, metadata, registerEnabled, ip, networkInterface,port, secure, accessKey, secretKey, heartBeatInterval, heartBeatTimeout,ipDeleteTimeout, instanceEnabled, ephemeral, failureToleranceEnabled,failFast

 

服务消费方

参考上述micro-svc-provider,在创建一个micro-svc-consumer作为服务消费方。

其他一模一样,更改一个项目名称就行了,EchoController内容如下:

@RefreshScope
@RestController
public class EchoController {
    // 客户端负载均衡器
    @Autowired
    private LoadBalancerClient loadBalancerClient;
    @Autowired
    private RestTemplate restTemplate;
    @Value("${spring.application.name}")
    private String appName;
    @GetMapping("/echo/app-name")
    public String echoAppName() {
        //Access through the combination of LoadBalanceClient and RestTemplate
        ServiceInstance serviceInstance = loadBalancerClient.choose(Consts.PROVIDER_SVC_ID);
        String path = String.format("http://%s:%s/echo/%s", serviceInstance.getHost(), serviceInstance.getPort(), appName);
        System.out.println("request path:" + path);
        return restTemplate.getForObject(path, String.class);
    }
}

现在我们启动两个服务提供方实例,端口分别是8081、8079;而消费方实例端口为8082:

图片

【from micro-svc-provider】env=test-application-provider,msg=from-micro-svc-provider-test.yaml-modified,port=8081,param=micro-svc-consumer

【from micro-svc-provider】env=test-application-provider,msg=from-micro-svc-provider-test.yaml-modified,port=8079,param=micro-svc-consumer

可以看到provider被轮询方式请求了。如果不想被轮询可以配置其他策略,也可以通过权重进行调整流量倾斜。

图片

至此,我们本篇入门笔记就结束了。其中涉及的点比较简单,一些深入细节等以后随着使用的深入,在开新篇记录。

总结

大概总结下来,需要注意的内容如下:

1、spring-cloud 和spring-clod-alibaba版本对齐问题

2、spring-cloud 配置中心请求配置放在bootstrap-{env}.yml内,否则可能会读取不到配置

3、config和discovery配置时,需要注意相关属性

4、注解@Value的默认值设置,否则启动时可能会报错

5、订阅者名称显示unknown的话,在项目启动参数中设置-Dproject.name=xxx解决

references

  • https://nacos.io/zh-cn/docs/what-is-nacos.html

39260spring cloud nacos 集成服务注册和发现,配置管理

这个人很懒,什么都没留下

文章评论