Nacos的简单介绍
Nacos(官网)致力于帮助您发现、配置和管理您的微服务。它提供了一组简单实用的功能,使您能够实现动态服务发现、服务配置管理以及服务和流量管理。
Nacos 让您构建更轻松、更快捷,您可以使用Nacos on Cloud或编译运行源代码来发布和管理微服务平台。它是支持采用微服务或云原生方法的以服务为中心的现代应用程序架构的基础设施。
Nacos 提供了四大功能
- 服务发现和服务健康检查: Nacos 使服务可以轻松注册自己并通过 DNS 或 HTTP 接口发现其他服务。Nacos 还提供服务的实时健康检查,以防止向不健康的主机或服务实例发送请求。Nacos 支持传输层 (PING 或 TCP)和应用层 (如 HTTP、MySQL、用户自定义)的健康检查。 对于复杂的云环境和网络拓扑环境中(如 VPC、边缘网络等)服务的健康检查,Nacos 提供了 agent 上报模式和服务端主动检测2种健康检查模式。Nacos 还提供了统一的健康检查仪表盘,帮助您根据健康状态管理服务的可用性及流量。动态服务发现对以服务为中心的(例如微服务和云原生)应用架构方式非常关键。
- 动态配置管理: 动态配置服务允许您在所有环境中以集中和动态的方式管理所有服务的配置。Nacos消除了在配置更新时重新部署应用程序和服务的需要,这使得配置更改更加高效和敏捷。动态配置服务可以让您以中心化、外部化和动态化的方式管理所有环境的应用配置和服务配置。动态配置消除了配置变更时重新部署应用和服务的需要,让配置管理变得更加高效和敏捷。配置中心化管理让实现无状态服务变得更简单,让服务按需弹性扩展变得更容易。Nacos 提供了一个简洁易用的UI (控制台样例 Demo) 帮助您管理所有的服务和应用的配置。Nacos 还提供包括配置版本跟踪、金丝雀发布、一键回滚配置以及客户端配置更新状态跟踪在内的一系列开箱即用的配置管理特性,帮助您更安全地在生产环境中管理配置变更和降低配置变更带来的风险。
- 动态 DNS 服务: Nacos 支持加权路由,让您在数据中心内的生产环境中更轻松地实现中间层负载均衡、灵活的路由策略、流量控制和简单的 DNS 解析服务。它可以帮助您轻松实现基于 DNS 的服务发现,以消除耦合到厂商私有服务发现API上的风险。
- 服务和元数据管理: Nacos 提供易于使用的可视化界面,帮助您管理服务元数据、配置、kubernetes DNS、服务健康和指标统计。Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略、服务的 SLA 以及最首要的 metrics 统计数据。
Nacos 地图
(图片来自https://nacos.io/zh-cn/docs/what-is-nacos.html)
与Spring Cloud Alibaba的版本关系
Spring Cloud Alibaba版本关系:
本博客使用
Spring Boot 2.3.12
Spring Cloud Alibaba 2.2.7
nacos 2.0.3
Nacos的下载与运行部署
有两种方式,一种是下载二进制文件编译运行,另一种是使用docker部署。(我这里采用docker 部署,二进制文件下载编译运行做个简单的介绍)
二进制文件下载编译运行
你可以下载二进制文件,然后使用脚本运行Nacos server
Nacos各种版本的下载地址
最新版是2.0.4,但是客户端好像还没有及时更新,所以先用2.0.3也没啥关系
Windows下载:直接下载zip后缀的nacos-server压缩包。
Windows运行
startup.cmd -m standalone
Linux下载
在tar.gz文件上面鼠标右键复制链接地址,然后使用wget命令进行下载。
wget https://github.com/alibaba/nacos/releases/download/2.0.4/nacos-server-2.0.3.tar.gz
解压
tar -zxvf nacos-server-2.0.3.tar.gz
cd到脚本所在文件夹,然后使用脚本文件运行Nacos服务
./startup.sh -m standalone
docker 拉取镜像运行
docker hub中的nacos
我下载2.0.3版本,和spring cloud版本和spirng boot版本对应使用
docker pull nacos/nacos-server:v2.0.3
运行一个基本的nacos-server尝尝鲜,nacos 2.0要放开这两个端口
9848 是nacos 2.0 新增的客户端gRPC请求服务端端口,用于客户端向服务端发起连接和请求
docker run -itd --name nacos-quick -e MODE=standalone -p 8848:8848 -p 9848:9848 nacos/nacos-server:v2.0.3
查询宿主机端口8848和9848是否开放
firewall-cmd --query-port=8848/tcp
firewall-cmd --query-port=9848/tcp
如果是no,输入如下命令对外开放这两个端口
firewall-cmd --permanent --add-port=8848/tcp
firewall-cmd --permanent --add-port=9848/tcp
重启防火墙(修改配置后要重启防火墙),让修改生效
firewall-cmd --reload
去服务器的控制台去开启防火墙,
如果是阿里云,还需要在安全组里面手动添加端口 ,配置可由那些IP访问。不然你防火墙开放了端口也是没用的。
访问管理界面(要加/nacos路径,因为有默认配置server.servlet.contextPath=/nacos)
服务器ip:8848/nacos
默认账号和密码都是nacos
登录默认账户密码进入
Nacos服务注册与发现的基本介绍与使用
动态服务发现对以服务为中心的(例如微服务和云原生)应用架构方式非常关键。Nacos支持DNS-Based和RPC-Based(Dubbo、gRPC)模式的服务发现。Nacos也提供实时健康检查,以防止将请求发往不健康的服务实例。
服务(Service)是Nacos世界的一等公民。Nacos支持几乎所有主流类型的服务的发现、配置和管理:
- Kubernetes Service
- gRPC & Dubbo RPC Service
- Spring Cloud RESTful Service
Eureka也有服务注册与发现的功能,但由于Eureka2.0闭源,以及Nacos本身的优势(服务在线管理、配置动态刷新等)。
功能 | Nacos | Eureka | 说明 |
---|---|---|---|
注册中心 | 是 | 是 | 服务治理基本功能,负责服务中心化注册 |
配置中心 | 是 | 否 | Eureka 需要Config 的配合来实现配置中心,且不提供管理界面 |
配置动态刷新 | 是 | 否 | Eureka 需要Config 、MQ 以及Webhook 的配合来实现配置动态刷新,而Nacos 采用Netty 保持TCP 长连接实时推送 |
可用区AZ | 是 | 是 | 对服务集群划分不同区域,实现区域隔离,并提供容灾自动切换 |
分组 | 是 | 否 | Nacos 可以根据业务和环境进行分组管理 |
元数据 | 是 | 是 | 提供服务标签数据,例如环境或服务标识 |
权重 | 是 | 否 | Nacos 默认提供权重设置功能,调整承载流量压力 |
健康检查 | 是 | 是 | Nacos 支持由客户端或服务端发起的健康检查,Eureka 是由客户端发起心跳 |
负载均衡 | 是 | 是 | 均提供负责均衡策略,Eureka 采用Ribbon |
管理界面 | 是 | 否 | Nacos 支持对服务在线管理,Eureka 只是预览服务状态 |
代码基本结构
创建主工程 springcloud,选择maven,直接–>next
填写项目相关信息
创建子项目:
在项目上:右键–>new–>module–>maven–>next
创建一个nacos-provider 子module
再同样创建一个nacos-consumer子module
nacos-consumer结构如下
nacos-provider结构如下
总体结构如下
代码相关文件
根项目
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.xt</groupId><artifactId>springcloud</artifactId><packaging>pom</packaging><version>1.0-SNAPSHOT</version><modules><module>nacos-provider</module><module>nacos-consumer</module></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.12.RELEASE</version></parent><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><spring-cloud-alibaba-version>2.2.7.RELEASE</spring-cloud-alibaba-version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version>${
spring-cloud-alibaba-version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.22</version><scope>provided</scope></dependency></dependencies></dependencyManagement></project>
nacos-consumer 子项目
向nacos server 注册这个项目,消费nacos-provider 服务
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springcloud</artifactId><groupId>com.xt</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>nacos-consumer</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></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>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies></project>
application.yml 配置文件
server:port: 8085spring:application:name: nacos-consumercloud:nacos:discovery:server-addr: 部署nacos server的服务器IP:8848
controller
package com.xt.springcloud.controller;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;@RestController
public class TestController {
private final RestTemplate restTemplate;@Autowiredpublic TestController(RestTemplate restTemplate) {
this.restTemplate = restTemplate;}@RequestMapping(value = "/echo/{str}", method = RequestMethod.GET)public String echo(@PathVariable String str) {
return restTemplate.getForObject("http://nacos-provider/echo/" + str, String.class);}
}
启动类
可以使用2种方式来消费服务,一种是RestTemplate,一种是Feign,我这里采用第一种
package com.xt.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;@SpringBootApplication
@EnableDiscoveryClient
public class NacosConsumerApplication {
@Bean@LoadBalancedpublic RestTemplate restTemplate() {
return new RestTemplate();}public static void main(String[] args){
SpringApplication.run(NacosConsumerApplication.class, args);}}
nacos-provider 子项目
向nacos server注册服务,给nacos-provider 消费提供服务
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springcloud</artifactId><groupId>com.xt</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>nacos-provider</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies></project>
application.yml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>springcloud</artifactId><groupId>com.xt</groupId><version>1.0-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>nacos-provider</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target></properties><dependencies><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency></dependencies></project>
实体类,我用来统计每个nacos-provider服务提供了多少次服务
package com.xt.springcloud.entity;import lombok.Data;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;import java.util.concurrent.atomic.AtomicInteger;@Component
@Data
public class CountNumber {
AtomicInteger atomicInteger;public CountNumber(){
this.atomicInteger = new AtomicInteger();}}
service 层
package com.xt.springcloud.service;import com.xt.springcloud.entity.CountNumber;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Service;@Service
public class EchoService {
@AutowiredCountNumber countNumber;public int queryCount(){
return countNumber.getAtomicInteger().get();}public void addOnce(){
countNumber.getAtomicInteger().addAndGet(1);}
}
controller
package com.xt.springcloud.controller;import com.xt.springcloud.service.EchoService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;import java.util.concurrent.atomic.AtomicInteger;@RestController
public class EchoController {
@AutowiredEchoService echoService;@GetMapping("/")public ResponseEntity index() {
return new ResponseEntity("index error", HttpStatus.INTERNAL_SERVER_ERROR);}@GetMapping("/error")public ResponseEntity test() {
return new ResponseEntity("error", HttpStatus.INTERNAL_SERVER_ERROR);}@GetMapping("/echo/{string}")public String echo(@PathVariable String string) {
echoService.addOnce();String ans = "hello Nacos Discovery :" + string;int cnt = echoService.queryCount();ans += "我是"+3+"号生产者实例";//演示的时候我这里手动更改这个打印,和这个字符串,以使得每个输出更加清晰,每运行一个服务,改动一下ans+="我被调用了"+cnt+"次";System.out.println(ans);return ans;}
}
启动类
package com.xt.springcloud;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;@SpringBootApplication
@EnableDiscoveryClient
public class NacosProviderApplication {
public static void main(String[] args) {
SpringApplication.run(NacosProviderApplication.class,args);}}
测试运行(同时测试负载均衡情况)
我打算启动三个nacos-provider提供服务(如下是已经配置好了),点击IDEA右上角如图所示的地方
添加spring boot应用
如图所示的添加,添加两个
然后依次启动每一个nacos-provider 服务,记得每run一次,要更改一次application.yml的配置文件的端口号,不然会端口冲突
将三个nacos-provider服务和一个nacos-consumer服务启动以后,我们可以到nacos 提供的管理页面去查看
http://服务器ip:8848/nacos
在nacos 提供的管理页面可以看到我们运行的服务实例已经被注册到了nacos server上面
还可以对服务进行管理,编辑,下线,调整负载均衡时候的权重等等
同时这里可以看到服务,集群以及实例级别的元数据信息,可以在控制台修改填充元数据,也可以使用application.yml文件进行设置
元数据信息可以帮助描述详细信息,还可以用来做版本控制
我们采用nacos-consumer来对nacos-provider发起10次请求,来看看nacos-provider的消费情况
我发现在我向consumer发出10次请求,而consumner向provider发起10次请求的过程中,1,2,3号provider实例轮番上阵,这可能说明nacos的默认负载均衡策略是轮询(但是也不一定,因为只是从表面现象看是这样,要去看源码才能有所了解)
在nacos 提供的控制台页面修改1号provider实例的权重为100之后,再发动10次请求,结果表面还是轮询,看来控制台的修改权重并没有起到作用。那么看起来很可能是nacos的负载均衡并没有起到作用。
因为我们这里也是使用的@LoadBalanced注解来实现客户端负载均衡的
而@LoadBalanced注解实现客户端负载均衡的底层使用了Ribbon组件
同时,我们在nacos-discovery的包里面可以发现,他依赖了ribbon组件
而Nacos已经实现了自定义的IRule实现类NacosRule。因此需要将NacosRule实例变成bean,便于Spring容器管理,修改NacosConsumerApplication类如下:重启NacosConsumerApplication
package com.xt.springcloud;import com.alibaba.cloud.nacos.ribbon.NacosRule;
import com.netflix.loadbalancer.IRule;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.web.client.RestTemplate;/*** @Author: codingXT* @Date: 2022-01-22-14:29* @Description:*/@SpringBootApplication
@EnableDiscoveryClient
public class NacosConsumerApplication {
@Bean@LoadBalancedpublic RestTemplate restTemplate() {
return new RestTemplate();}@Bean@Scope(value = "prototype")public IRule loadBalanceRule() {
return new NacosRule();}public static void main(String[] args){
SpringApplication.run(NacosConsumerApplication.class, args);}}
然后重启nacos-consumer服务让他生效,其他provider可以不用重启。
我这里都重启了,然后修改8081号端口的1号provider服务实例的权重为100
192.168.56.1是我的以太网适配器 VirtutalBox Host-Only Network 的IP地址
这块网卡是virtualbox的虚拟网卡,应该是IDEA自动装上去的,用作验证服务器使用。(我也不是很清楚,有知道的大佬评论区踢我一下)
使用postman来发起批量请求300次,来看看nacos 控制台的权重修改是否生效
postman批量发送多个请求 可以看这个
请求300次,run开始批量请求
然后1号provider实例被调用了296次
2号provider实例被调用了3次
3号provider实例被调用了1次
看样子nacos的负载均衡起到了作用,大部分请求都被转发到1号provider实例去了
服务的注册与发现的基本原理
服务注册
Spring Cloud Nacos Discovery 遵循了 spring cloud common 标准,实现了 AutoServiceRegistration、ServiceRegistry、Registration 这三个接口。
在 spring cloud 应用的启动阶段,监听了 WebServerInitializedEvent 事件,当Web容器初始化完成后,即收到 WebServerInitializedEvent 事件后,会触发注册的动作,调用 ServiceRegistry 的 register 方法,将服务注册到 Nacos Server。
服务发现
NacosServerList 实现了 com.netflix.loadbalancer.ServerList 接口,并在 @ConditionOnMissingBean 的条件下进行自动注入,默认集成了Ribbon。
如果需要有更加自定义的可以使用 @Autowired 注入一个 NacosRegistration 实例,通过其持有的 NamingService 字段内容直接调用 Nacos API。
nacos的其他配置项:
配置项 | key | 默认值 | 说明 |
---|---|---|---|
服务端地址 | spring.cloud.nacos.discovery.server-addr | ||
服务名 | spring.cloud.nacos.discovery.service | spring.application.name | |
权重 | spring.cloud.nacos.discovery.weight | 1 | 取值范围 1 到 100,数值越大,权重越大 |
网卡名 | spring.cloud.nacos.discovery.network-interface | 当IP未配置时,注册的IP为此网卡所对应的IP地址,如果此项也未配置,则默认取第一块网卡的地址 | |
注册的IP地址 | spring.cloud.nacos.discovery.ip | 优先级最高 | |
注册的端口 | spring.cloud.nacos.discovery.port | -1 | 默认情况下不用配置,会自动探测 |
命名空间 | spring.cloud.nacos.discovery.namespace | 常用场景之一是不同环境的注册的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。 | |
AccessKey | spring.cloud.nacos.discovery.access-key | ||
SecretKey | spring.cloud.nacos.discovery.secret-key | ||
Metadata | spring.cloud.nacos.discovery.metadata | 使用Map格式配置 | |
日志文件名 | spring.cloud.nacos.discovery.log-name | ||
接入点 | spring.cloud.nacos.discovery.endpoint | UTF-8 | 地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址 |
是否集成Ribbon | ribbon.nacos.enabled | true |
References:
- https://github.com/alibaba/nacos/wiki/
- https://kaven.blog.csdn.net/article/details/121207295
- https://nacos.io/zh-cn/
- https://nacos.io/en-us/docs/quick-start-spring-cloud.html
- https://github.com/alibaba/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-examples/nacos-example/nacos-discovery-example/readme-zh.md
- https://www.cnblogs.com/yuer02/p/14785802.html
(写博客主要是对自己学习的归纳整理,资料大部分来源于书籍、网络资料和自己的实践,整理不易,但是难免有不足之处,如有错误,请大家评论区批评指正。同时感谢广大博主和广大作者辛苦整理出来的资源和分享的知识。)