介绍

Naocs官方文档:

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

安装

Nacos独立服务

Nacos需要独立的运行服务。到官方的git上去下载最新的release版本:

https://github.com/alibaba/nacos/releases

下载后解压,运行/bin/startup.cmd:
startup
可以看到其端口为8848。
然后打开浏览器,输入地址:

http://localhost:8848/nacos/index.html#/login

输入用户名和密码:nacos/nacos,即可登录控制台。注意需要等startup.cmd加载完毕才可可登陆,否则会提示用户名或密码错误。
控制台左侧有4个标签:

  • 配置管理
  • 服务管理
  • 命名空间
  • 集群管理

可以在这里对4个标签下的内容进行动态修改。
Nacos除了可视化方式维护,还可以通过http请求来修改。官方api文档地址:

https://nacos.io/zh-cn/docs/open-api.html

官方文档已经明确说明了各种请求的调用方式,特别要注意请求是get还是post必须按要求使用,否则调用是无效的。

配置管理

SpringBoot将配置存储在.properties文件中。当修改了.properties文件,就必须重新打包部署。
naocs配置管理的作用类似SpringBoot的.properties,SpringBoot可以从中远程获取其定义的配置。
nacos提供的是动态配置功能:在nacos中可以添加多个配置集,每个配置集下可以有多个配置项。然后在SpringBoot中即可动态获取到这些配置项的值。当nacos中配置集的配置项修改后,SpringBoot对其的引用也会及时更新。

集成到Spring Boot

  1. 在pom.xml中添加依赖:

    <!--nacos-->
    <dependency>
        <groupId>com.alibaba.boot</groupId>
        <artifactId>nacos-config-spring-boot-starter</artifactId>
        <version>${latest.version}</version>
    </dependency>
    

    其中最新的版本号可以查看Nacos的Maven仓库:

    https://mvnrepository.com/artifact/com.alibaba.boot/nacos-config-spring-boot-starter

    注意版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本。

  2. 在.properties中配置Nacos server的地址:

    nacos.config.server-addr=127.0.0.1:8848
    

    若没有该配置项,则工程无法启动,控制台会提示endpoint is blank

配置集设置

配置集设置有2种方式:

  1. 后台可视化设置。直接登录后台并设置。注意新建配置时的配置格式需要选择Properties
  2. http请求设置。

配置集需要指定dataIdgroup

  • group:即配置分组,用于较广的分类,通常使用工程名,表示其下配置属于指定工程。一个group下可以有多个配置集,且不同的group下可以存在同id的配置集。
  • dataId:即配置集id,需要指定属于哪个group。一个配置集下可有多个配置项。通常用于同一类配置的多个配置项,例如指定数据库连接池的多个配置项放入同一个配置集中。

实际使用中,group使用工程名,然后其下建立多个dataId,每个dataId下都添加多项同类配置项。

http请求设置

例如,要向Nacos server发布配置:dataIdtest,内容为testValue=abc123

http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=test&group=DEFAULT_GROUP&content=testValue=abc123

注意请求必须为post

使用

配置集中的配置项有2种使用方式:直接引用和导入配置文件。这两种方式都支持配置的动态更新(可控制开启/关闭)。

直接引用

所谓直接引用就是在SpringBoot中直接以注解形式获取nacos中配置集的配置项值。

  1. 使用 @NacosPropertySource 注解在XXXApplication中加载dataIdtest的配置源,并开启自动更新

    @SpringBootApplication
    @NacosPropertySource(dataId = "test", autoRefreshed = true)
    public class TestApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(TestApplication.class, args);
        }
    }
    
  2. 通过Nacos的@NacosValue注解获取属性值。

    @CrossOrigin
    @RestController
    public class ConfigController {
    
        @NacosValue(value = "${testValue:false}", autoRefreshed = true)
        private String testValue;
    
        @RequestMapping("/getTestValue")
        public String getTestValue() {
            return testValue;
        }
    }
    

    即将nacos中test配置集下的配置项testValue赋给了ConfigController的成员变量testValue,从而可以在该类任何方法中使用。

  3. 启动工程,调用:

    http://localhost:8080/getTestValue

    返回内容是abc123

导入配置

导入配置即将nacos中的指定配置集导入到.properties中,就像这些配置是被定义在.properties中的一样。使用时,直接从.properties中加载指定配置项即可。

  1. 将配置导入到.properties中:

    nacos.config.ext-config[0].dataId=test
    nacos.config.ext-config[0].group=DEFAULT_GROUP
    nacos.config.ext-config[0].auto-refresh=true
    
  2. 从.properties中加载指定配置项:

    @CrossOrigin
    @RestController
    public class ConfigController {
        @Autowired
        private Environment env;
    
        @RequestMapping("/getTestValue")
        public String getTestValue() {
            return env.getProperty("testValue");
        }
    }
    
  3. 启动工程,调用:

    http://localhost:8080/getTestValue

    返回内容是abc123

服务管理

nacos可用于服务管理。具体来说就是:nacos中可以创建服务。一些工程可以将自己注册为指定服务的提供者,而另一些工程可以申请使用指定服务。于是nacos就作为服务的中转来将已注册的服务提供给需要的工程。
例如,nacos注册了2个服务A、B。

  1. 初始状态,没有工程注册为这2个服务的实例,即提供者。于是服务A、B是不可用的。
  2. 有2个工程A1、B1分别申请注册为服务A、B的实例。于是服务A、B变为可用。
  3. 此时有一个工程X从nacos获取服务A、B。工程X拿到服务实例后,可以访问每个实例的所有接口。
  4. 用户直接访问工程X,工程X借助nacos获取2个服务的实例从而访问工程A1、B1的接口,并将访问结果返回给用户。2个工程A1、B1对用户透明。
  5. 对于每个服务,nacos可以配置集群。即nacos的服务A下可以有工程A1、A2…等多个工程来提供相同的服务。当工程X请求时,随机分配可用的实例。

根据整个流程,nacos的服务管理分两部分:

  1. 服务注册:服务提供者工程将自身注册给nacos,来作为可用服务。
  2. 服务使用:用户访问的工程从nacos中获取服务,并访问服务的各个接口来获得对应返回。

集成到Spring Boot

无论是服务提供者还是服务使用者,都需要将nacos服务管理依赖集成到SpringBoot,并且二者的集成是相同的。
注意服务管理的依赖与配置管理的依赖是不同的:配置管理用的依赖是xx-config-xx,配置管理用的依赖是xx-discovery-xx

  1. 在pom.xml中添加依赖:

    <!--nacos-->
    <dependency>
      <groupId>com.alibaba.boot</groupId>
      <artifactId>nacos-discovery-spring-boot-starter</artifactId>
      <version>${latest.version}</version>
    </dependency>
    

    其中最新的版本号可以查看Nacos的Maven仓库:

    https://mvnrepository.com/artifact/com.alibaba.boot/nacos-discovery-spring-boot-starter

    注意版本 0.2.x.RELEASE 对应的是 Spring Boot 2.x 版本,版本 0.1.x.RELEASE 对应的是 Spring Boot 1.x 版本。

  2. 在.properties中配置Nacos server的地址:

    nacos.discovery.server-addr=127.0.0.1:8848
    

服务注册

新建一个名为server的工程作为服务提供者这里将其服务端口设为8081。按前述步骤添加依赖并配置配置Nacos server的地址。在其中实现具体的接口,可正常通过请求访问即可。
为了测试,实现一个可访问接口:

@CrossOrigin
@RestController
public class ServerController {

    @RequestMapping("/getServerValue")
    public String getServerValue(HttpServletRequest request) {
        String message = request.getParameter("message");
        return "the server receives the message : " + message;
    }
}

该接口接收一个名为messageString类型参数,并拼接到字符串末尾返回。为了方便测试,该接口这里同时可接收getpost请求。
为了实现服务注册,添加一个配置类:

@Configuration
public class ServerRegisterConfig {
    @NacosInjected
    private NamingService namingService;

    @PostConstruct
    public void registerInstance() throws NacosException {
        String serviceName = "server";
        String groupName = "web";
        Instance instance = new Instance();
        instance.setIp("127.0.0.1");
        instance.setPort(8081);
        instance.setHealthy(true);
        instance.setWeight(1.0);
        namingService.registerInstance(serviceName, groupName, instance);
    }
}

这里调用instance.setWeight()配置了权重。权重为浮点数,值越大,分配给该实例的流量越大。通过Instance还可以设置其他各种属性。
这样,当工程启动时就会执行该逻辑,从而将本工程注册为nacos中分组名称为web,服务名为server的服务。
之所以写成配置类仅仅是为了启动时自动执行。也可以将该逻辑写在一个接口中,通过调用接口触发。
工程启动后,查看nacos后台,可以看到服务已经注册成功:
serverRegister

点击其中的详情可以看到支持集群配置,可以有多个工程申请为同一服务。

保护阈值

nacos会检查服务下的各个实例(Instance)的健康状态,并判定该实例为健康或者不健康。当需要将服务实例返回给请求者时,不健康的实例不会被返回。
然而按照该策略,当出现了不健康实例,nacos就不会再返回该实例,而是只返回剩余的健康实例,这样会导致剩余的健康实例压力增大。于是剩余的健康实例变为不健康实例的几率就会增大。
一旦在剩余的健康实例中出现不健康实例,nacos依然执行相同策略,于是剩余的健康实例数量继续减少,压力继续增大。这样下去,所有的健康实例都会被压垮,形成雪崩效应。
服务的保护阈值就是为了防止该问题。保护阈值的范围是[0,1]之间的一个浮点数,用于表示百分比。其作用是:当一个服务的健康实例的占比小于该数时,则无论当前服务的各个实例是否健康,都将被返回。这样可能造成部分请求出现问题,但可以保证集群剩余健康实例正常工作。

服务使用

新建一个名为client的工程作为服务使用者这里使用默认的服务端口8080。按前述步骤添加依赖并配置配置Nacos server的地址。
在需要调用server服务的地方使用@NacosInjected注解引入nacos服务对象:

@CrossOrigin
@RestController
public class ClientController {
    @Autowired
    private RestTemplate restTemplate;
    @NacosInjected
    private NamingService namingService;

    /**
     * get方式传参调用nacos服务
     */
    @RequestMapping("/getClientValueByGet")
    public String getClientValueByGet(HttpServletRequest request) {
        String serviceName = "server";
        String groupName = "web";
        String api = "/getServerValue";
        try {
            String message = request.getParameter("message");
            Instance instance = namingService.selectOneHealthyInstance(serviceName, groupName);
            String url = "http://" + instance.getIp() + ":" + instance.getPort() + api + "?" + "message=" + message;
            String r = restTemplate.getForObject(url, String.class);
            return r;
        } catch (Exception e) {
            return "";
        }
    }

    /**
     * post方式传参调用nacos服务
     */
    @RequestMapping("/getClientValueByPost")
    public String getClientValueByPost(HttpServletRequest request) {
        String serviceName = "server";
        String groupName = "web";
        String api = "/getServerValue";
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);

            String message = request.getParameter("message");
            MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
            map.add("message", message);

            HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(map, headers);

            Instance instance = namingService.selectOneHealthyInstance(serviceName, groupName);
            String url = "http://" + instance.getIp() + ":" + instance.getPort() + api;
            String r = restTemplate.postForObject(url, httpEntity, String.class);
            return r;
        } catch (Exception e) {
            return "";
        }
    }
}

该类提供的两个接口分别使用getpost方式调用nacos的server服务的接口并传入message参数。
通过NamingService.selectOneHealthyInstance()获取的Instance中包含了服务提供者所有的必要信息。
这里使用了RestTemplate来进行服务的远程调用,也可以使用其他方式。
启动工程,在浏览器中访问:

http://localhost:8080/getClientValueByGet?message=test
http://localhost:8080/getClientValueByPost?message=test

两个请求的返回相同:

the server receives the message : test

其他

NacosNamingService还提供了一些其他的方法,例如NacosNamingService.getAllInstances()

List<Instance> NacosNamingService.getAllInstances(String serviceName)
List<Instance> NacosNamingService.getAllInstances(String serviceName, String groupName)
List<Instance> NacosNamingService.getAllInstances(String serviceName, String groupName, List<String> clusters, boolean subscribe)

通常使用NacosNamingService.getAllInstances(String serviceName, String groupName)。返回的是一个List<Instance>,每个Instance是nacos中的一个注册服务,即一个服务提供者工程的信息。其结构为:

[
  {
    "instanceId": "127.0.0.1-8080-DEFAULT-example",
    "ip": "127.0.0.1",
    "port": 8080,
    "weight": 1.0,
    "healthy": true,
    "cluster": {
      "serviceName": null,
      "name": "",
      "healthChecker": {
        "type": "TCP"
      },
      "defaultPort": 80,
      "defaultCheckPort": 80,
      "useIPPort4Check": true,
      "metadata": {}
    },
    "service": null,
    "metadata": {}
  }
]

但通过Instance无法得知该工程有哪些接口。通常地,由前端传入serviceName和groupName(若groupName是已知的则可不传),然后再将这两个参数交给NamingService使用。
通过NacosNamingService无法查询服务列表,但直接调用nacos API可以做到:

127.0.0.1:8848/nacos/v1/ns/service/list?pageNo=1&pageSize=10

命名空间

命名空间的隔离粒度最大,不同的命名空间下可以添加同名的Group及服务。命名空间主要用于环境的隔离,例如开发环境/生产环境等。
命名空间只有2个属性:命名空间名和描述。
创建一个命名空间后,在配置管理、服务管理和集群管理页面的最上方可以切换不同的命名空间。

集群管理

查看各个节点的信息。不能修改。

其他配置

在SpringBoot工程的.properties中可用的各种nacos.config以及nacos.discovery官方提供了文档:

https://github.com/nacos-group/nacos-spring-boot-project/wiki/spring-boot-0.2.2-%E4%BB%A5%E5%8F%8A-0.1.2%E7%89%88%E6%9C%AC%E6%96%B0%E5%8A%9F%E8%83%BD%E4%BD%BF%E7%94%A8%E6%89%8B%E5%86%8C

文档右上角的目录列出了所有版本的升级日志。

  1. nacos.config

    # 开启配置预加载功能
    nacos.config.bootstrap.enable=true
    
    # 主配置服务器地址
    nacos.config.server-addr=192.168.16.104:8848
    # 主配置 data-id
    nacos.config.data-id=people
    # 主配置 group-id
    nacos.config.group=DEFAULT_GROUP
    # 主配置 配置文件类型
    nacos.config.type=properties
    # 主配置 最大重试次数
    nacos.config.max-retry=10
    # 主配置 开启自动刷新
    nacos.config.auto-refresh=true
    # 主配置 重试时间
    nacos.config.config-retry-time=2333
    # 主配置 配置监听长轮询超时时间
    nacos.config.config-long-poll-timeout=46000
    # 主配置 开启注册监听器预加载配置服务(除非特殊业务需求,否则不推荐打开该参数)
    nacos.config.enable-remote-sync-config=true
    
    nacos.config.ext-config[0].data-id=test
    nacos.config.ext-config[0].group=DEFAULT_GROUP
    nacos.config.ext-config[0].max-retry=10
    nacos.config.ext-config[0].type=yaml
    nacos.config.ext-config[0].auto-refresh=true
    nacos.config.ext-config[0].config-retry-time=2333
    nacos.config.ext-config[0].config-long-poll-timeout=46000
    nacos.config.ext-config[0].enable-remote-sync-config=true
    
    # 支持日志级别的加载时机,可配合dubbo使用
    nacos.config.bootstrap.log.enable=true
    
    # 支持配置data-ids的设置方式
    nacos.config.data-ids=people,test
    nacos.config.group=DEVELOP
    nacos.config.type=properties
    nacos.config.auto-refresh=true
    nacos.config.max-retry=10
    nacos.config.config-retry-time=2333
    nacos.config.config-long-poll-timeout=46000
    nacos.config.enable-remote-sync-config=true
    
  2. nacos.discover

    # 是否允许服务自动注册(默认为关闭自动注册)
    nacos.discovery.auto-register=true
    # 服务对外暴露 ip
    nacos.discovery.register.ip=1.1.1.1
    # 服务对外暴露 port
    nacos.discovery.register.port=1
    # 服务权重
    nacos.discovery.register.weight=0.6D
    # 服务健康信息
    nacos.discovery.register.healthy=false
    # 服务是否可用
    nacos.discovery.register.enabled=true
    # 是否为临时实例
    nacos.discovery.register.ephemeral=true
    # 服务集群名称
    nacos.discovery.register.clusterName=SPRINGBOOT
    # 服务所属分组
    nacos.discovery.register.groupName=BOOT
    # 服务名称
    nacos.discovery.register.serviceName=SPRING_BOOT_SERVICE
    
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐