文章目录
介绍
Naocs官方文档:
https://nacos.io/zh-cn/docs/what-is-nacos.html
安装
Nacos独立服务
Nacos需要独立的运行服务。到官方的git上去下载最新的release版本:
https://github.com/alibaba/nacos/releases
下载后解压,运行/bin/startup.cmd:
可以看到其端口为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
-
在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 版本。
-
在.properties中配置Nacos server的地址:
nacos.config.server-addr=127.0.0.1:8848
若没有该配置项,则工程无法启动,控制台会提示endpoint is blank。
配置集设置
配置集设置有2种方式:
- 后台可视化设置。直接登录后台并设置。注意新建配置时的配置格式需要选择Properties。
- http请求设置。
配置集需要指定dataId
和group
。
- group:即配置分组,用于较广的分类,通常使用工程名,表示其下配置属于指定工程。一个group下可以有多个配置集,且不同的group下可以存在同id的配置集。
- dataId:即配置集id,需要指定属于哪个group。一个配置集下可有多个配置项。通常用于同一类配置的多个配置项,例如指定数据库连接池的多个配置项放入同一个配置集中。
实际使用中,group
使用工程名,然后其下建立多个dataId
,每个dataId
下都添加多项同类配置项。
http请求设置
例如,要向Nacos server发布配置:dataId
为test
,内容为testValue=abc123
:
http://127.0.0.1:8848/nacos/v1/cs/configs?dataId=test&group=DEFAULT_GROUP&content=testValue=abc123
注意请求必须为post。
使用
配置集中的配置项有2种使用方式:直接引用和导入配置文件。这两种方式都支持配置的动态更新(可控制开启/关闭)。
直接引用
所谓直接引用就是在SpringBoot中直接以注解形式获取nacos中配置集的配置项值。
-
使用 @NacosPropertySource 注解在XXXApplication中加载
dataId
为test
的配置源,并开启自动更新:@SpringBootApplication @NacosPropertySource(dataId = "test", autoRefreshed = true) public class TestApplication { public static void main(String[] args) { SpringApplication.run(TestApplication.class, args); } }
-
通过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
,从而可以在该类任何方法中使用。 -
启动工程,调用:
http://localhost:8080/getTestValue
返回内容是
abc123
。
导入配置
导入配置即将nacos中的指定配置集导入到.properties中,就像这些配置是被定义在.properties中的一样。使用时,直接从.properties中加载指定配置项即可。
-
将配置导入到.properties中:
nacos.config.ext-config[0].dataId=test nacos.config.ext-config[0].group=DEFAULT_GROUP nacos.config.ext-config[0].auto-refresh=true
-
从.properties中加载指定配置项:
@CrossOrigin @RestController public class ConfigController { @Autowired private Environment env; @RequestMapping("/getTestValue") public String getTestValue() { return env.getProperty("testValue"); } }
-
启动工程,调用:
http://localhost:8080/getTestValue
返回内容是
abc123
。
服务管理
nacos可用于服务管理。具体来说就是:nacos中可以创建服务。一些工程可以将自己注册为指定服务的提供者,而另一些工程可以申请使用指定服务。于是nacos就作为服务的中转来将已注册的服务提供给需要的工程。
例如,nacos注册了2个服务A、B。
- 初始状态,没有工程注册为这2个服务的实例,即提供者。于是服务A、B是不可用的。
- 有2个工程A1、B1分别申请注册为服务A、B的实例。于是服务A、B变为可用。
- 此时有一个工程X从nacos获取服务A、B。工程X拿到服务实例后,可以访问每个实例的所有接口。
- 用户直接访问工程X,工程X借助nacos获取2个服务的实例从而访问工程A1、B1的接口,并将访问结果返回给用户。2个工程A1、B1对用户透明。
- 对于每个服务,nacos可以配置集群。即nacos的服务A下可以有工程A1、A2…等多个工程来提供相同的服务。当工程X请求时,随机分配可用的实例。
根据整个流程,nacos的服务管理分两部分:
- 服务注册:服务提供者工程将自身注册给nacos,来作为可用服务。
- 服务使用:用户访问的工程从nacos中获取服务,并访问服务的各个接口来获得对应返回。
集成到Spring Boot
无论是服务提供者还是服务使用者,都需要将nacos服务管理依赖集成到SpringBoot,并且二者的集成是相同的。
注意服务管理的依赖与配置管理的依赖是不同的:配置管理用的依赖是xx-config-xx,配置管理用的依赖是xx-discovery-xx。
-
在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 版本。
-
在.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;
}
}
该接口接收一个名为message
的String
类型参数,并拼接到字符串末尾返回。为了方便测试,该接口这里同时可接收get
和post
请求。
为了实现服务注册,添加一个配置类:
@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后台,可以看到服务已经注册成功:
点击其中的详情可以看到支持集群配置,可以有多个工程申请为同一服务。
保护阈值
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 "";
}
}
}
该类提供的两个接口分别使用get
和post
方式调用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
文档右上角的目录列出了所有版本的升级日志。
-
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
-
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