阿里的一个开源产品,是针对微服务架构中的服务发现、配置管理、服务治理的综合型解决方案。
(用来实现配置中心和服务注册中心)
在微服务架构中一个业务流程需要多个微服务通过网络接口调用完成业务处理,服务消费方从服务注册中心获取服 务提供方的地址,从而进行远程调用,这个过程叫做服务发现。
存在的问题:
在微服务架构中,整个系统会按职责能力划分为多个服务,通过服务之间协作来实现业务目标。服务的消费方要调用服务的生产方,为了完成一次请求,消费方需要知道服务生产方的网络位置(IP地址和端口号)。
微服务可能是部署在云环境的,服务实例的网络位置或许是动态分配的。
每个服务一般会有多个实例来做负载均衡,由于宕机或升级,服务实例网络地址会经常动态改变。
每个服务也可能应对临时访问压力增加新的服务节点。
服务发现就是服务消费方通过服务发现中心智能发现服务提供方,从而进行远程调用的过程。
服务实例本身并不记录服务生产方的网络地址,所有服务实例内部都会包含服务发现客户端。
在每个服务启动时会向服务发现中心上报自己的网络位置。在服务发现中心内部会形成一个服务注册表,服务注册表是服务发现的核心部分,是包含所有服务实例的网络地址的数据库。
服务发现客户端会定期从服务发现中心同步服务注册表 ,并缓存在客户端。
当需要对某服务进行请求时,服务实例通过该注册表,定位目标服务网络地址。若目标服务存在多个网络地址,则使用负载均衡算法从多个服务实例中选择出一个,然后发出请求。
总结,在微服务环境中,由于服务运行实例的网络地址是不断动态变化的,服务实例数量的动态变化 ,因此无法使用固定的配置文件来记录服务提供方的网络地址,必须使用动态的服务发现机制用于实现微服务间的相互感知。 各服务实例会上报自己的网络地址,这样服务中心就形成了一个完整的服务注册表,各服务实例会通过服务发现中心来获取访问目标服务的网络地址,从而实现服务发现的机制。
目前市面上用的比较多的服务发现中心有:Nacos、Eureka、Consul和Zookeeper。
Nacos 需要依赖一定的环境:
下载源码或者安装包
从Github上下载源码方式
#从GitHub中下载Nacos
git clone https://github.com/alibaba/nacos.git
#进入Nacos中
cd nacos/
#安装
mvn ‐Prelease‐nacos clean install ‐U
ls ‐al distribution/target/
// change the $version to your actual path
cd distribution/target/nacos‐server‐$version/nacos/bin
下载编译后压缩包方式
下载地址:https://github.com/alibaba/nacos/releases
可以从最新稳定版本下载 nacos-server-$version.zip 包,本教程使用nacos-server-1.1.3版本。
下载后解压:
unzip nacos‐server‐$version.zip #或者
tar ‐xvf nacos‐server‐$version.tar.gz
cd nacos/bin
启动服务器
nacos的默认端口是8848,需要保证8848默认端口没有被其他进程占用。 进入安装程序的bin目录:
Linux/Unix/Mac启动方式:
#启动命令(standalone代表着单机模式运行,非集群模式)
sh startup.sh -m standalone
#如果是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:
bash startup.sh -m standalone
Windows启动方式:
#启动命令:
cmd startup.cmd
#双击startup.cmd运行文件。
检验是否启动成功:浏览器访问 http://127.0.0.1:8848/nacos (启动后会显示访问的地址,如本次访问的是:http://10.7.163.85:8848/nacos/index.html),会打开nacos控制台登录页面;
使用默认用户名:nacos,默认密码:nacos ;登录即可打开主页面。
外部mysql数据库支持
单机模式时nacos默认使用嵌入式数据库实现数据的存储,若想使用外部mysql存储nacos数据,需要进行以下步 骤:
安装数据库,版本要求:5.6.5+ ,mysql 8 以下
初始化mysql数据库,新建数据库nacos_config
,数据库初始化文件:${nacoshome}/conf/nacosmysql.sql
修改${nacoshome}/conf/application.properties
文件,增加支持mysql数据源配置(目前只支持 mysql),添加mysql数据源的url、用户名和密码。
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://11.162.196.16:3306/nacos_config?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=root
db.password=123456
在nacos-discovery父工程中添加依赖管理
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring‐boot‐dependenciesartifactId>
<version>2.1.3.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring‐cloud‐dependenciesartifactId>
<version>Greenwich.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring‐cloud‐alibaba‐dependenciesartifactId>
<version>2.1.0.RELEASEversion>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
分别在服务提供及服务消费工程中添加依赖,此依赖的作用是服务发现
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring‐cloud‐starter‐alibaba‐nacos‐discoveryartifactId>
dependency>
服务注册:在服务提供工程中配置nacos服务发现相关的配置:
服务提供:
spring:
application:
name: nacos‐restful‐provider
cloud:
nacos:
discovery:
server‐addr: 127.0.0.1:8848
启动nacos(启动服务提供),观察nacos服务列表,nacos-restful-provider注册成功。
服务名:每个服务在服务注册中心的标识,相当于Java中的类名。
服务实例:网络中提供服务的实例,具有IP和端口,相当于Java中的对象,一个实例即为运行在服务器上的一个进 程。
服务发现:在服务消费工程中配置nacos服务发现相关的配置:
服务消费:
spring:
application:
name: nacos‐restful‐consumer
cloud:
nacos:
discovery:
server‐addr: 127.0.0.1:8848
服务消费
/*改Controller中远程调用的代码*/
//服务id即注册中心的中的服务名 private String serviceId="nacos‐restful‐provider";
@Autowired
LoadBalancerClient loadBalancerClient;
@GetMapping(value = "/service")
public String service(){
RestTemplate restTemplate = new RestTemplate();
//调用服务
//String providerResult = restTemplate.getForObject("http://" + providerAddress + "/service",String.class);
ServiceInstance serviceInstance = loadBalancerClient.choose(serviceId);
URI uri = serviceInstance.getUri();
String providerResult = restTemplate.getForObject(uri+"/service",String.class);
return "consumer invoke | " + providerResult; }
执行流程:
在RESTful服务发现的流程中,ServiceA通过负载均衡调用ServiceB;
负载均衡就是将用户请求(流量)通过一定的策略,分摊在多个服务实例上执行,它是系统处理高并发、缓解网络压力和进行服务端扩容的重要手段之一。
它分为服务端负载均衡和客户端负载均衡。
在负载均衡器中维护一个可用的服务实例清单,当客户端请求时,负载均衡服务器按照某种配置好的规则(负载均衡算法)从可用服务实例清单中选取其一去处理客户端的请求。这就是服务端负载均衡。
例如Nginx,通过Nginx进行负载均衡,客户端发送请求至Nginx,Nginx通过负载均衡算法,在多个服务器 之间选择一个进行访问。即在服务器端再进行负载均衡算法分配。
上边使用的LoadBalancerClient就是一个客户端负载均衡器,具体使用的是Ribbon客户端负载均衡器。 Ribbon在发送请求前通过负载均衡算法选择一个服务实例,然后进行访问,这是客户端负载均衡。即在客户端就进行负载均衡的分配。
Ribbon是一个客户端负载均衡器,其责任是从一组实例列表中挑选合适的实例,如何挑选,取决于负载均衡策略 。
Ribbon核心组件IRule是负载均衡策略接口,实现:
在服务消费方的配置文件中修改默认的负载均衡策略:
nacos‐restful‐provider: #服务提供方的服务名称
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule
#com.netflix.loadbalancer.RandomRule:负载均衡类路径
启动多个服务提供方进程,为保证端口不冲突,通过启动参数配置端口,并启动这两个进程。
启动参数配置端口会优先于配置文件中的配置;
Dubbo是阿里巴巴公司开源的RPC框架,其微服务开发组件相对Spring Cloud来说并不那么完善。
Spring Cloud Alibaba微服务开发框架集成了Dubbo,可实现微服务对外暴露Dubbo协议的接口,Dubbo协议相 比RESTful协议速度更快。
RPC:RPC是远程过程调用(Remote Procedure Call),调用RPC远程方法就像调用本地方法一样,非常方便。
微服务采用Dubbo协议的系统架构图:
组件说明:
交互流程:
优势分析:
此架构同时提供RESTful和Dubbo接口服务,应用层对前端提供RESTful接口,RESTful是互联网通用的轻量级交互协议,方便前端接入系统;微服务层向应用层提供Dubbo接口,Dubbo接口基于RPC通信协议速度更快。
本架构采用阿里开源的Nacos,集服务发现和配置中心于一身,支持RESTful及Dubbo服务的注册。
需要依赖
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring‐cloud‐starter‐dubboartifactId>
dependency>
定义配置文件bootstrap.yml
server:
port: 56040 #启动端口 命令行注入
spring:
application:
name: dubbo‐service2
main:
allow‐bean‐definition‐overriding: true # Spring Boot 2.1 需要设定
cloud:
nacos:
discovery:
server‐addr: 127.0.0.1:8848
dubbo:
scan:
# dubbo 服务扫描基准包
base‐packages: com.itheima.microservice.service2.service
protocol:
# dubbo 协议
name: dubbo
# dubbo 协议端口
port: 20891
registry:
address: nacos://127.0.0.1:8848
application:
qos‐enable: false #dubbo运维服务是否开启
consumer:
check: false #启动时就否检查依赖的服务
bootstrap.yml
配置说明:
bootstrap.yml内容中以dubbo开头的为dubbo服务的配置:
dubbo.scan.base-packages
:指定 Dubbo 服务实现类的扫描基准包,将 @org.apache.dubbo.config.annotation.Service
注解标注的service暴露为dubbo服务。dubbo.protocol
:Dubbo 服务暴露的协议配置,其中子属性 name 为协议名称, port 为dubbo协议端口,可以指定多协议,如:dubbo.protocol.rmi.port=1099
dubbo.registry
:Dubbo 服务注册中心配置,其中子属性 address 的值 nacos://127.0.0.1:8848
,说明 dubbo服务注册到nacos 相当于原生dubbo的xml配置中的 bootstrap.yml内容的上半部分为SpringCloud的相关配置:
spring.application.name
:Spring 应用名称,用于 Spring Cloud 服务注册和发现。dubbo.application.name
,因此无需再显示地配置 dubbo.application.name
spring.cloud.nacos.discovery
:Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器 主机和端口定义接口实现
注意:使用@org.apache.dubbo.config.annotation.Service
标记dubbo服务
package com.itheima.microservice.service2.service;
import com.itheima.microservice.service2.api.Service2Api;
@org.apache.dubbo.config.annotation.Service
public class Service2ApiImpl implements Service2Api {
public String dubboService2() {return "dubboService2";} }
启动service2-server:启动成功观察nacos的服务列表;
application1调用service2
引用service2
<dependency>
<groupId>com.itheima.nacosgroupId>
<artifactId>service2‐apiartifactId>
<version>1.0‐SNAPSHOTversion>
dependency>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring‐cloud‐starter‐dubboartifactId>
dependency>
实现远程调用
修改nacos-restful-consumer工程的RestConsumerController:
@org.apache.dubbo.config.annotation.Reference
private Service2Api service2Api;
@GetMapping(value = "/service2")
public String service2(){ //远程调用service2
String providerResult = service2Api.dubboService2();
return "consumer dubbo invoke | " + providerResult;}
注意:@Reference
注解是 org.apache.dubbo.config.annotation.Reference
请求:http://127.0.0.1:56020/service2
显示:consumer dubbo invoke | dubboService2 表明service2调用成功。
命名空间(Namespace)用于进行租户粒度的隔离,Namespace 的常用场景之一是不同环境的隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
命名空间(Namespace)是用于隔离多个环境的(如开发、测试、生产),而每个应用在不同环境的同一个配置(如数据库数据源)的值是不一样的。因此,我们应针对企业项目实际研发流程、环境进行规划。 如某软件公司拥有开发、测试、生产三套环境,那么我们应该针对这三个环境分别建立三个namespace。
建立好所有namespace后,在配置管理与服务管理模块下所有页面,都会包含用于切换namespace(环境)的tab按钮;
注意:
namesace 为 public 是 nacos 的一个保留空间,如需要创建自己的 namespace,不要和 public 重名,以一个实际业务场景有具体语义的名字来命名,以免带来字面上不容易区分哪一个 namespace。
在编写程序获取配置集时,指定的namespace参数一定要填写命名空间ID,而不是名称
Nacos在经过阿里内部多年生产经验后提炼出的数据模型,是一种 服务-集群-实例 的三层模型,这样基本可以满 足服务在所有场景下的数据存储和管理。
服务:对外提供的软件功能,通过网络访问预定义的接口。
实例:提供一个或多个服务的具有可访问网络地址(IP:Port)的进程,启动一个服务,就产生了一个服务实例。
元信息:Nacos数据(如配置和服务)描述信息,如服务版本、权重、容灾策略、负载均衡策略、鉴权配置、各种自定义标 签 (label),
从作用范围来分:服务级别的元信息、集群的元信息、实例的元信息。
集群:服务实例的集合,服务实例组成一个默认集群, 集群可以被进一步按需求划分,划分的单位可以是虚拟集群,相同集群下的实例才能相互感知。
应用通过Namespace、Service、Cluster(DEFAULT)的配置,描述了该服务向哪个环境(如开发环境)的哪个集群注册实例。
例子:
指定namespace的id:a1f8e863-3117-48c4-9dd3-e9ddc2af90a8(注意根据自己环境设置namespace的id)
指定集群名称:DEFAULT表示默认集群,可不填写
spring:
application:
name: transaction‐service
cloud:
nacos:
discovery:
server‐addr: 127.0.0.1:7283 # 注册中心地址
namespace: a1f8e863‐3117‐48c4‐9dd3‐e9ddc2af90a8 #开发环境
cluster‐name: DEFAULT #默认集群,可不填
集群作为实例的隔离,相同集群的实例才能相互感知。
namespace、cluster-name若不填写都将采取默认值,namespace的默认是public命名空间, cluster-name的默认值为DEFAULT集群。
在微服务架构中为了统一管理各微服务的配置信息专门设置配置中心,配置中心就是一种统一管理各种应用配置的基础服务组件。
应用程序在启动和运行的时候往往需要读取一些配置信息,配置基本上伴随着应用程序的整个生命周期,比如:数据库连接参数、启动参数等。
配置特点:
微服务架构中,当系统从一个单体应用,被拆分成分布式系统上一个个服务节点后,配置文件也必须跟着迁移 (分割),这样配置就分散了,同时分散中还包含着冗余
配置中心将配置从各应用中剥离出来,对配置进行统一管理,应用自身不需要自己去 管理配置。
配置中心的服务流程:
配置中心就是一种统一管理各种应用配置的基础服务组件。
配置中心是整个微服务基础架构体系中的一个组件。
总结:在传统巨型单体应用纷纷转向细粒度微服务架构的历史进程中,配置中心是微服务化不可缺少的一个系统组件,在这种背景下中心化的配置服务即配置中心应运而生;配置中心特性:
目前市面上用的比较多的配置中心有:Spring Cloud Config、Apollo、Nacos和Disconf等。 Disconf不再维护。
性能方面Nacos的读写性能最高,Apollo次之,Spring Cloud Config依赖Git场景不适合开放的大规模自动化运维API。
功能方面Apollo最为完善,nacos具有Apollo大部分配置管理功能,而Spring Cloud Config不带运维管理界面,需要自行开发。
Nacos的一大优势是整合了注册中心、配置中心功能,部署和操作相比 Apollo都要直观简单,因此它简化了架构复杂度,并减轻运维及部署工作。
综合来看:Nacos的特点和优势还是比较明显的。
发布配置
首先在nacos发布配置,nacos-restful-consumer服务从nacos读取配置。 浏览器访问 http://127.0.0.1:8848/nacos ,打开nacos控制台,并点击菜单配置管理->配置列表:
在Nacos添加如下的配置: nacos-restful-consumer:
Namespace: public
Data ID: nacos‐restful‐consumer.yaml
Group : DEFAULT_GROUP
配置格式: YAML
配置内容: common:
name: application1 config
获取配置:从配置中心获取配置添加nacos-config的依赖:
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring‐cloud‐starter‐alibaba‐nacos‐configartifactId>
dependency>
在bootstrap.yml
添加配置:
spring:
cloud:
nacos:
config:
server‐addr: 127.0.0.1:8848 # 配置中心地址
file‐extension: yaml
group: DEFAULT_GROUP
注意:要使用配置中心就要在bootstrap.yml
中来配置,bootstrap.yml配置文件的加载顺序要比application.yml要优先。
在nacos-restful-consumer工程的controller中增加获取配置的web访问端点/configs,通过标准的spring @Value 方式。
@Value("${common.name}")
private String common_name;
@GetMapping(value = "/configs")
public String getvalue(){return common_name;}
若要实现配置的动态更新,只需要进行如下改造:
//注入配置文件上下文
@Autowired private ConfigurableApplicationContext applicationContext;
@GetMapping(value = "/configs")
public String getConfigs(){
return applicationContext.getEnvironment().getProperty("common.name"); }
通过nacos控制台更新common.name的配置值,再次访问web端点/configs,发现应用程序能够获取到最新 的配置值,说明spring-cloud-starter-alibaba-nacos-config 支持配置的动态更新。可以通过配置spring.cloud.nacos.config.refresh.enabled=false来关闭动态刷新
对于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为:STUDENT_GROUP。
命名空间(Namespace):
命名空间可用于进行不同环境的配置隔离。例如可以隔离开发环境、测试环境和生产环境,因为 它们的配置可能各不相同,或者是隔离不同的用户,不同的开发人员使用同一个nacos管理各自的配置,可通过 namespace隔离。不同的命名空间下,可以存在相同名称的配置分组(Group) 或 配置集。
常见实践用法:
Nacos抽象定义了Namespace、Group、Data ID的概念,具体这几个概念代表什么,取决于我们把它们看成什么,如:
Namespace:代表不同环境,如开发、测试、生产环境;
Group:代表某项目,如XX医疗项目、XX电商项目;
DataId:每个项目下往往有若干个工程,每个配置集(DataId)是一个工程的主配置文件
获取某配置集的代码:
获取配置集需要指定:
在config中指定namespace,例子如下:
config:
server‐addr: 127.0.0.1:8848 # 配置中心地址
file‐extension: yaml
namespace: a1f8e863‐3117‐48c4‐9dd3‐e9ddc2af90a8 #开发环境
group: DEFAULT_GROUP # xx业务组
group,如不指定默认 DEFAULT_GROUP;
dataId,必须指定,名称为应用名称+配置文件扩展名
Spring Cloud Alibaba Nacos Config可支持自定义 Data Id 的配置。
一个完整的配置案例如下所示:
spring:
application:
name: service2
cloud:
nacos:
config:
server‐addr: 127.0.0.1:8848 # 配置中心地址
file‐extension: yaml
#namespace: a1f8e863‐3117‐48c4‐9dd3‐e9ddc2af90a8 #开发环境
group: DEFAULT_GROUP
# config external configuration
# 1、Data Id group:组名,refresh:动态刷新
ext‐config[0]:
data‐id: ext‐config‐common01.yaml
group: COMMON_GROUP #组名
refresh: true
ext‐config[1]:
data‐id: ext‐config‐common02.yaml
group: COMMON_GROUP
refresh: true
通过 spring.cloud.nacos.config.ext-config[n].data-id
的配置方式来支持多个 Data Id 的配置。
通过 spring.cloud.nacos.config.ext-config[n].group
的配置方式自定义 Data Id 所在的组,不明确配置 的话,默认是 DEFAULT_GROUP。
通过 spring.cloud.nacos.config.ext-config[n].refresh
的配置方式来控制该 Data Id 在配置变更时,是否支持应用中可动态刷新, 感知到最新的配置值。默认是不支持的。
spring.cloud.nacos.config.ext-config[n].data-id
的值必须带文件扩展名,文件扩展名既可支持 properties,又可以支持 yaml/yml。 此时 spring.cloud.nacos.config.file-extension 的配置对自定义扩展配置的 Data Id 文件扩展名没有影响。
配置ext-config-common01.yaml:
测试:
@GetMapping(value = "/configs")
public String getvalue(){
String name = applicationContext.getEnvironment().getProperty("common.name");
String address = applicationContext.getEnvironment().getProperty("common.addr");
return name+address;}
重启nacos-restful-consumer工程,访问:http://127.0.0.1:56020/configs
注意:
扩展配置优先级是 spring.cloud.nacos.config.ext-config[n].data-id
其中 n 的值越大,优先级越高。 通过内部相关规则(应用名、扩展名 )自动生成相关的 Data Id 配置的优先级最大。