1 nacos简介
1.1nacos介绍
Nacos是阿里的一个开源产品,它是针对微服务架构中的服务发现、配置管理、服务治理的综合型解决方案。是微服务的注册中心和配置中心,相当于springcloudEureka和springconfig的集合。
Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集,帮助您实现动态服务发现、服务配置管理、服务及流量管理。 Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。
Nacos 是构建以“服务”为中心的现代应用架构的服务基础设施。
1.2nacos的特性
Nacos主要提供以下四大功能:
1. 服务发现与服务健康检查
Nacos使服务更容易注册,并通过DNS或HTTP接口发现其他服务,Nacos还提供服务的实时健康检查,以防止向不健康的主机或服务实例发送请求。
2. 动态配置管理
动态配置服务允许您在所有环境中以集中和动态的方式管理所有服务的配置。Nacos消除了在更新配置时重新部署应用程序,这使配置的更改更加高效和灵活。
3. 动态DNS服务
Nacos提供基于DNS 协议的服务发现能力,旨在支持异构语言的服务发现,支持将注册在Nacos上的服务以域名的方式暴露端点,让三方应用方便的查阅及发现。
4. 服务和元数据管理
Nacos 能让您从微服务平台建设的视角管理数据中心的所有服务及元数据,包括管理服务的描述、生命周期、服务的静态依赖分析、服务的健康状态、服务的流量管理、路由及安全策略。
这里动态配置管理的特性说明了Naocs的配置管理能力。
1.4nacos安装
1.下载链接:Releases · alibaba/nacos · GitHub
2.解压
3.在nacos bin文件夹下打开cmd窗口 输入sh startup.sh -m standalone启动成功
4.启动成功,可通过浏览器访问 http://127.0.0.1:8848/nacos ,打开如下nacos控制台登录页面
用户名和密码都是nacos
2.nacos作为注册中心
2.1结构设计
nacos-parent
------producer
------consumer
2.2pom文件引入
2.2.1父工程
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.qcby</groupId><artifactId>nacos-parent</artifactId><version>0.0.1-SNAPSHOT</version><packaging>pom</packaging><properties><java.version>1.8</java.version></properties><modules><module>producer</module><module>consumer</module></modules><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.0.RELEASE</version></parent><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.apache.httpcomponents</groupId><artifactId>httpclient</artifactId><version>4.5.5</version></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>0.2.2.RELEASE</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><dependency><groupId>com.alibaba.nacos</groupId><artifactId>nacos-client</artifactId><version>1.1.3</version></dependency><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId><version>2.1.0.RELEASE</version></dependency></dependencies></project>
2.子工程依赖直接引入父工程直接继承下来
<parent><groupId>com.qcby</groupId><artifactId>nacos-parent</artifactId><version>0.0.1-SNAPSHOT</version></parent>
在子工程中写入配置文件
server:port: 8081
spring:application:name: nacos-video-catcloud:nacos:discovery:server-addr: 127.0.0.1:8848
server:port: 8082
spring:application:name: nacos-video-vip
#想要在服务中显示的名字cloud:nacos:discovery:server-addr: 127.0.0.1:8848#nacos服务的端口
3.nacos网页上就有了
4.使用rest或httpclient或openfeign调用接口
4.1 rest方式调用
1.在消费者启动类下面加
@Beanpublic RestTemplate restTemplate(){return new RestTemplate();}
2.在生产端写一个接口我的生产端是
nacos-video-vip
@RestController
public class TestController {@Value("producer")String s;@RequestMapping("toShow")public String toShow(){return s;}
}
//随意写知道是生产端的结构就行
3.消费端调用
@RestControllerpublic class TestController {@Autowiredprivate DiscoveryClient discoveryClient;@Autowiredprivate RestTemplate restTemplate;@RequestMapping("getInfo")public String getInfo(){List<ServiceInstance> serviceInstances=discoveryClient.getInstances("nacos-video-vip");ServiceInstance serviceInstance=serviceInstances.get(0);String url="http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/" + "getMember";String s=restTemplate.getForObject(url,String.class);return s;}}
4.结果:
5.可能现在我展示的可能只有一个服务,但是以后大公司业务场景可能同一种服务部署在好几台服务器上,不可能所有的项目都用同一台服务器的服务,所以就会用到加载均衡算法。
5.1系统提供的LoadBalancerClient
@Autowiredprivate LoadBalancerClient loadBalancerClient;
@RequestMapping("/orderToMember5")public String orderToMember5(){ServiceInstance serviceInstance= loadBalancerClient.choose("producer");String numberUrl="http://"+serviceInstance.getHost()+":"+serviceInstance.getPort()+"/"+ "toShow";return "订单服务调用会员服务:" +restTemplate.getForObject(numberUrl,String.class);}
LoadBalancerClient默认走的随机,可以自己继承AbstractLoadBalancerRule重写算法
5.2随机算法模拟
@Component
public class RandomLoadBalance implements LoadBalance {@Autowiredprivate DiscoveryClient discoveryClient;@Overridepublic ServiceInstance getInstances(String serviceId) {//1.根据服务的名称 获取 该服务集群地址列表List<ServiceInstance> instances = discoveryClient.getInstances(serviceId);//2.判断是否nullif (instances == null || instances.size() == 0) {return null;}// 生成随机 范围Random random = new Random();//3 0 1 2int index = random.nextInt(instances.size());return instances.get(index);}
}
5.3轮询算法模拟
@Component
public class RoundLoadBalance implements LoadBalance{@Autowiredprivate DiscoveryClient discoveryClient;private AtomicInteger atomicCount=new AtomicInteger(0);@Overridepublic ServiceInstance getInstances(String serviceId) {List<ServiceInstance> instances=discoveryClient.getInstances(serviceId);if (instances==null||instances.size()==0){return null;}int index=atomicCount.incrementAndGet()%instances.size();return instances.get(index);}
5.4权重算法
@Component
public class WeightLoadBalance implements LoadBalance{@Autowiredprivate DiscoveryClient discoveryClient;private AtomicInteger atomicInteger=new AtomicInteger(0);@Overridepublic ServiceInstance getInstances(String serviceId) {List<ServiceInstance> serviceInstances = discoveryClient.getInstances(serviceId);if (serviceInstances == null) {return null;}ArrayList<ServiceInstance> newInstances = new ArrayList<>();for (ServiceInstance serviceInstance : serviceInstances) {Double weight = Double.parseDouble(serviceInstance.getMetadata().get("nacos.weight"));for (int i = 0; i < weight; i++) {newInstances.add(serviceInstance);}}return newInstances.get(atomicInteger.incrementAndGet() % newInstances.size());}
}
5.5错误转移算法
@Component
public class ErrorLoadBalance implements LoadBalance{@Autowiredprivate DiscoveryClient discoveryClient;@Autowiredprivate RestTemplate restTemplate;@Overridepublic ServiceInstance getInstances(String serviceId) {List<ServiceInstance> serviceInstances=discoveryClient.getInstances(serviceId);for (int i = 0; i < serviceInstances.size(); i++) {ServiceInstance serviceInstance=serviceInstances.get(i);String memberUrl = "http://" + serviceInstance.getHost() + ":" + serviceInstance.getPort() + "/" + "getMember";try {ResponseEntity<String> respone=restTemplate.getForEntity(memberUrl,String.class);if (respone==null){continue;}return serviceInstance;}catch (Exception e){}}return null;}
}
3.nacos作为配置中心
3.1Nacos配置管理基础应用
现如今,在微服务体系中,一个系统往往被拆分为多个服务,每个服务都有自己的配置文件,然后每个系统往往还会准备开发环境、测试环境、正式环境
我们来说算一算,假设某系统有10个微服务,那么至少有10个配置文件吧,三个环境(devtestprod),那就有30个配置文件需要进行管理。
这么多的配置文件,要修改一个或者多个的时候,稍有不慎可能就会出现改错了、不生效....等等问题。
对于Nacos配置管理,通过Namespace、group、Data ID能够定位到一个配置集。
- 配置集(Data ID)
在系统中,一个配置文件通常就是一个配置集,一个配置集可以包含了系统的各种配置信息,例如,一个配置集可能包含了数据源、线程池、日志级别等配置项。每个配置集都可以定义一个有意义的名称,就是配置集的ID即Data ID。
配置项
配置集中包含的一个个配置内容就是配置项。它代表一个具体的可配置的参数与其值域,通常以 key=value 的形
式存在。例如我们常配置系统的日志输出级别(logLevel=INFO|WARN|ERROR) 就是一个配置项。
- 配置分组(Group)
配置分组是对配置集进行分组,通过一个有意义的字符串(如 Buy 或 Trade )来表示,不同的配置分组下可以有相同的配置集(Data ID)。当您在 Nacos 上创建一个配置时,如果未填写配置分组的名称,则配置分组的名称默认采用 DEFAULT_GROUP 。配置分组的常见场景:可用于区分不同的项目或应用,例如:订单系统的配置集
可以定义一个group为:ORDER_GROUP。
- 命名空间(Namespace)
命名空间(namespace)可用于进行不同环境的配置隔离。例如可以隔离开发环境、测试环境和生产环境,因为它们的配置可能各不相同,或者是隔离不同的用户,不同的开发人员使用同一个nacos管理各自的配置,可通过namespace隔离。不同的命名空间下,可以存在相同名称的配置分组(Group) 或配置集。
最佳实践
Nacos抽象定义了Namespace、Group、Data ID的概念,具体这几个概念代表什么,取决于我们把它们看成什么,这里推荐给大家一种用法,如下图:
Namespace:代表不同环境,如开发、测试、生产环境。
Group:代表某微服务中的工程
DataId:每个项目下往往有若干个工程,每个配置集(DataId)是一个工程的主配置文件
3.2单环境下“读取”Nacos中相应的配置
在之前环境上,父工程加入依赖
<!-- SpringCloud Ailibaba Nacos Config -->
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
spring:application:name: nacos-video-vipcloud:nacos:discovery:server-addr: 127.0.0.1:8848config:server-addr: 127.0.0.1:8848name: nacos-video-vip#name为naocos配置中心中创建的配置文件去掉后缀file-extension: ymlgroup: DEFAULT_GROUP
3.3多环境下“读取”Nacos中相应的配置
比如说,你一个项目有test和run等等环境的配置文件,但是项目名一样,如何区分呢?
比如run环境下,配置文件名改为nacos-video-vip-run.yml
spring:application:name: nacos-video-vipcloud:nacos:discovery:server-addr: 127.0.0.1:8848config:server-addr: 127.0.0.1:8848prefix: ${spring.application.name}#prefix为注册中心的名称,尽量写为项目名file-extension: ymlgroup: DEFAULT_GROUPprofiles:active: run
3.4Group方案
上面介绍了通过指定spring.profile.active和配置文件的DataID来使不同环境下读取不同的配置这里也可以不用DataID,直接通过Group实现环境区分
注:这种方式不太推荐,切换不灵活,需要切换环境时要改Gruop配置
spring:application:name: nacos-video-vipcloud:nacos:discovery:server-addr: 192.168.0.108:8848config:server-addr: 192.168.0.108:8848prefix: ${spring.application.name}file-extension: ymlgroup: RUN_GROUP
3.5Namespace方案
Namespace命名空间进行环境隔离也是官方推荐的一种方式。Namespace的常用场景之一是不同环境的配置的区分隔离,例如:开发测试环境和生产环境的资源(如配置、服务)隔离等。
spring:application:name: nacos-video-vipcloud:nacos:discovery:server-addr: 192.168.0.108:8848config:server-addr: 192.168.0.108:8848prefix: ${spring.application.name}file-extension: ymlnamespace: 6c339ea2-cb77-4f2c-843e-aefe8315bf6f
通过上面三种方案的介绍,想必大家对于多环境下的配置读取方式应该有所选择
DataID: 适用于项目不多,服务量少的情况。
Group:实现方式简单,但是容易与DataID方案发生冲突,仅适合于本地调试
Namespace:实现方式简单,配置管理简单灵活,同时可以结合DataID共同使用,推荐这种方案
3.6多环境下“管理”及“隔离”配置和服务命名空间管理
当我们的服务达到一定的数量,集中式的管理许多服务会十分不便,
那我们可以将这些具有相同特征或属性的服务进行分组管理,服务对应的配置也进行分组隔离
这里的分组就是Namespace的概念,将服务和配置纳入相同的Namespace进行管理
不同Namespace下的服务和配置之间就隔离开来。
创建和获取NamespaceID
NamespaceId值是在配置文件配置时必须要填入的配置项,所以需要我们先创建Namespace和Id,步骤如下:
nacos 的控制台左边功能栏看到有一个 命名空间 的功能,点击就可以看到 新建命名空间 的按钮新建成功后,可以在命名空间列表中查看到你所创建的Namespace和他生成的ID值这里只是讲解创建步骤。
创建开发和测试环境
Namespace实施方案
例如,你可能有dev,test和prod三个不同的环境,那么使用一套 nacos 集群可以分别建以下三个不同的 namespace。如下图所示:
通过定义不同的环境,不同环境的项目在不同的Namespace下进行管理,不同环境之间通过Namespace进行隔离当多个项目同时使用该Nacos集群时,还可以通过Group进行Namespace内的细化分组
这里以Namespace:dev为例,在Namespace中通过不同Group进行同一环境中不同项目的再分类
3.7nacos共享配置
一个项目中服务数量增加后,配置文件相应增加,多个配置文件中会存在相同的配置,那么我们可以将相同的配置独立出来,作为该项目中各个服务的共享配置文件,每个服务都可以通过Nacos进行共享配置的读取
下面用一个demo演示下,是否可行
demo工程:nacos-config-share
配置文件:nacos-config-share.yml
共享配置文件:shareconfig1.yml,shareconfig2.yml
创建项目
一如往常,还是在聚合工程Nacos下创建名为nacos-config-share的子工程,其pom.xml文件依赖与之前的项目都一致
- 修改springboot启动类NacosConfigShareApplication.java
@SpringBootApplication
@RestController
@RefreshScope@EnableDiscoveryClient
public class NacosConfigShareApplication {public static void main(String[] args) {SpringApplication.run(NacosConfigShareApplication.class, args);}@Value("${nacos.share}")private String share;@Value("${share.config1}")private String shareConfig1;@Value("${share.config2}")private String shareConfig2;@RequestMapping("/getValue")public String getValue() {return share;}@RequestMapping("/getShare1")public String getShare1() {return shareConfig1;}@RequestMapping("/getShare2")public String getShare2() {return shareConfig2;}
}
修改该项目的配置文件bootstrap.yml
spring:application:name: nacos-config-sharecloud:nacos:discovery:server-addr: 192.168.0.108:8848config:server-addr: 192.168.0.108:8848prefix: ${spring.application.name}file-extension: ymlshared-dataids: shareconfig1.yml,shareconfig2.ymlrefreshable-dataids: shareconfig1.yml,shareconfig2.yml
创建配置文件nacos-config-share.yml,详细如下:
DataId:nacos-config-share.yml
配置格式:YAML
配置内容:
server: port: 9984 nacos: share: nacos-config-share |
创建共享配置文件1 shareconfig1.yml,详细如下:
DataId:shareconfig1.yml
配置格式:YAML
配置内容:
share: config1: 这里是共享配置文件1 |
创建共享配置文件2 shareconfig2.yml,详细如下:
DataId:shareconfig2.yml
配置格式:YAML
配置内容:
share: config2: 这里是共享配置文件2 |
-
- 启动测试
从日志中我们可以看到配置文件的加载
访问启动类中提供的接口,测试下能否获取到共享配置文件中的值
访问127.0.0.1:9984/getValue,返回:nacos-config-share
访问127.0.0.1:9984/getShare1,返回:这里是共享配置文件1
访问127.0.0.1:9984/getShare2,返回:这里是共享配置文件2
再测试下refreshable-dataids配置的自动刷新是否生效
在Nacos控制台中修改共享配置文件shareconfig2.yml的值为:这里是共享配置文件2update
编辑保存后,重新请求 127.0.0.1:9984/getShare2 ,观察返回结果如下:
以上返回结果说明通过在配置文件中指定shared-dataids和refreshable-dataids是可以实现共享配置文件的读取和自动刷新的。