在我前面的系列已经为大家介绍了Spring Cloud Config
,可以实现将分布式微服务的配置进行集中管理。但是,就目前而言,我们目前仅限于在应用程序启动时更新此类配置。将属性的新值推送到Git
之后,我们将需要手动重新启动每个应用程序进程以获得新值,或者通过手动发送“/actuator/refresh”
请求的方式实现配置刷新。如果我们想要实现应用配置的热更新,单纯依靠Spring Cloud Config
就无能为力了,那就需要结合我们本节开始为大家讲的Spring Cloud Bus
才能够实现。
Spring Cloud Bus
将分布式系统的微服务通过轻量级的消息中间件连接起来,通过消息中间件广播状态更改(例如配置更改)或其他管理指令。总线就像是横向扩展的Spring Boot
应用程序的分布式的actuator
,它也可以用作微服务之间的通信渠道。
消息总线的核心工作逻辑
:将收到的消息(事件)批量分发到所有或部分的微服务节点应用,微服务应用在接到消息之后做出相应的业务处理相应。Spring Cloud Bus
不仅可以分发配置刷新消息(事件),还可以应用到整个微服务系统中的其他业务Spring Cloud Bus
是基于消息队列产品实现的,从官网来看目前支持的消息队列有两种:rabbitMQ和kafka
。Spring Cloud Bus
的消息分发机制,是基于消息队列的:发布/订阅模式实现的。笔者要说明的是:目前互联网上的很多关于Spring Cloud Bus的架构图都有一个错误,那就是“/bus/refresh”数据刷新请求是由config server接收的。实际这种理解是错误的,接收“/bus/refresh”请求的是Spring Cloud Bus。比如下面的这张图就是错误的。
在Spring Boot2.0中“/bus/refresh”服务端点不再被开放,而是使用“/actuator/bus-refresh”代替。需要结合Spring Cloud Bus与spring-boot-starter-actuator一起使用。
上面这种图之所以会画错,我猜可能是因为这个原因:我们在使用Spring cloud微服务架构的时候,为了降低微服务组件的复杂度,Spring cloud Bus和Spring CLoud Config通常是一起使用的,也就是说将Spring Cloud Bus是集成到Spring Cloud Config Server里面的,使用同一个JVM进程实例。导致Config Server看上去就是Spring Cloud Bus,二者是物理集成,逻辑分离。
架构图如下所示:
这里注意获取镜像的时候要获取management版本的,不要获取last版本的,management版本的才带有管理界面。
本文使用docker快速安装部署一个RabbitMQ镜像,只是为了方便学习,不适用于生产。RabbitMQ等消息中间件知识不是本文核心内容,后文我们结合RabbitMQ单节点来为大家讲解Spring Cloud Bus。所以本节我们需要先安装RabbitMQ
前提是你的服务器已经成功安装了docker。
docker pull rabbitmq:management
使用rabbitMQ镜像运行一个实例,暴露5672和15672端口。
docker run -d -p 5672:5672 -p 15672:15672 --name rabbitmq rabbitmq:management
看到如下结果,容器启动成功了:
可以用docker ps
查看正在运行的docker 容器
开放端口。因为使用到了5672和15672端口对外提供服务,所以需要在防火墙上开放端口(以CentOS7防火墙为例)
firewall-cmd --zone=public --add-port=5672/tcp --permanent;
firewall-cmd --zone=public --add-port=15672/tcp --permanent;
firewall-cmd --reload
访问管理界面的地址就是 http://[宿主机IP]:15672,可以使用默认的账户登录,用户名和密码都guest,如:
到这里就完成安装部署了。
通过maven坐标引入必须依赖
<!--添加基于RabbitMQ的Spring Cloud Bus的支持 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!--在Spring Boot2.0版本需要actuator提供刷新请求接口:“/actuator/bus-refresh” -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
加上如下配置:指定RabbitMQ消息中间件的服务地址。因为我们的Spring Cloud Bus作为消息发布者向rabbitMQ中放入“配置刷新”消息,所以需要rabbit的地址及认证信息。
spring:
rabbitmq:
host: 192.168.128.1
port: 5672
username: guest
password: guest
加上如下配置:暴露配置刷新服务端点。
笔者在使用当前版本做实验的时候单独暴露bus-refresh是不生效的(访问结果是405),笔者在之前版本实验过是生效的(下文代码注释掉的部分)。找不到任何理由,我猜想可能是版本bug,所以我是用的是include:"*"来完成任务。虽然开放了actuator的所有服务端点,但是我们加上Spring security认证也提升安全性。
如果你的config server和我一样引入了spring-boot-starter-security,把下面的代码配置加入。否则通过“/actuator/bus-refresh”访问将会报错:401,没有权限访问。
@Configuration
public class ConfigServerWebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
// 都是无状态请求,不需要session,节省资源
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
//关闭csrf跨站请求防御
http.csrf().disable();
// 所有的请求必须登录认证后才能访问
http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
}
}
登录RabbitMQ管理界面,有一个channel表示我们已经成功集成rabbitMQ
显示如下topic,表示我们成功集成了Spring Cloud Bus
PostMan访问:“http://localhost:8771/actuator/bus-refresh” ,响应结果为204(虽然暂时我们没有RabbitMQ的消息接收端,但是不影响请求测试)
之前的章节,我们先后为大家介绍了netflix公司为Spring Cloud社区贡献的一系列技术方案:
所以在正确的完成了eureka client相关配置,config client相关配置,我们的微服务想具备spring cloud bus提供的配置刷新能力,需要做如下的配置
比如:dhy-service-rbac和dhy-service-sms,集成Bus提供的配置刷新能力
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
加上RabbitMQ消息队列的配置(加到git仓库对应微服务的配置文件中)
spring:
rabbitmq:
host: 192.168.161.3
port: 5672
username: guest
password: guest
之前是访问单节点http://localhost:8401/actuator/refresh
进行单节点配置刷新,现在访问Bus
的http://localhost:8771/actuator/bus-refresh
进行所有实例的配置刷新。
之前我们讲的/actuator/bus-refresh
是刷新所有在eureka
上注册,并且连接了config server
微服务实例的配置。假如我们希望局部刷新实例需要使用:/actuator/bus-refresh/{destination}
,这样消息总线上的微服务实例就会根据destination参数的值来判断某个微服务实例是否需要刷新。
这种刷新方式虽然提供了一定的灵活性,但远远达不到灰度发布的要求。所以Spring Cloud Config整体上还是有一定的局限性。
默认情况下,
ApplicationContext ID
是spring.application.name:server.port
,详见org.springframework.boot.context.ContextIdApplicationContextInitializer.getApplicationId(ConfigurableEnvironment)
方法。
本章我们开始为大家介绍nacos,nacos是alibaba开发的是用于微服务管理的平台,其核心功能是服务注册与发现、集中配置管理。有了之前的一系列相关的技术的学习,nacos学习起来还是非常简单的,使用也很简单。
当然Nacos作为一个微服务管理平台,除了面向spring Cloud,还支持很多其他的微服务基础设施,如:docker、dubbo、kubernetes等。除了核心的服务注册与发现和配置管理功能,还提供了各种服务管理的功能特性,如:动态DNS、服务元数据管理等。
为什么叫nacos?Naming与Configuration的前两个字母的组合,最后的s代表service。从其命名也能看出其核心功能。
虽然nacos现在已经升级到2.0版本,但是部署方式没有发生变化.本文使用的1.0版本的安装部署方式仍然适用。
Nacos支持单点部署的模式,搭建过程非常简单,实际上nacos的standalone模式没有所谓的安装过程,就是下载和启动。但是这种情况没有高可用支持,所以只适合测试或学习使用。
首先去nacos的github地址下载release安装包。当然你也可以自己下载源码之后进行编译打包,nacos是使用java开发的,使用maven进行编译打包。这里我们就不自己打包了,使用release安装包。下载地址是:https://github.com/alibaba/nacos/releases。在linux系统下可以使用如下的命令下载和解压缩。
#下载nacos
wget https://github.com/alibaba/nacos/releases/download/1.2.1/nacos-server-1.2.1.tar.gz;
# 解压nacos
tar -xvf nacos-server-1.2.1.tar.gz
进入到nacos/bin目录下面,startup命令用于启动nacos,shutdown命令用于停掉nacos。
nacos的默认服务端口是8848,启动完成之后通过浏览器访问nacos:http://ip:8848/nacos/。看到如下界面,需要登陆,默认的用户名密码都是nacos,登陆之后看到如下界面:
如果你访问不到上面的界面,请检查你部署的主机操作系统的防火墙设置。以下是为CentOS7系统防火墙开放8848端口的命令,其他系统请自行解决。
firewall-cmd --zone=public --add-port=8848/tcp --permanent
firewall-cmd --reload
如果仍然访问不到,可能是服务器多网卡导致的。可以参考下一节“集群安装”中的处理方法。
nacos的单机standalone模式安装对于新人可以说是非常的友好,几乎不需要的更多的操作就可以搭建nacos单节点,方便大家学习使用。另外,单机standalone模式安装默认是使用了nacos应用本身的嵌入式数据库apache derby,我们可以使用MySQL替换它。使用外置MySQL数据库,和“集群安装”对于数据库的要求是一样的,我们下节再讲。
我准备了三台服务器(虚拟机),192.168.161.3、192.168.161.4、192.168.161.5。在三台服务器上分别下载、解压nacos安装包,并在防火墙开放8848端口(参考单机部署standalone部署的模式的操作)。然后我们开始nacos集群模式的安装。
数据库db、用户需要自己去创建,nacos-mysql.sql文件只有建表语句和初始化用户nacos的INSERT语句。
在192.168.161.3、192.168.161.4、192.168.161.5都要配置。
spring.datasource.platform=mysql
db.num=1
db.url.0=jdbc:mysql://192.168.161.3:3306/nacosdb?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=test
db.password=
在192.168.161.3、192.168.161.4、192.168.161.5都要配置。如果没有这个文件,就新建一个。
#ip:port
192.168.161.3:8848
192.168.161.4:8848
192.168.161.5:8848
在192.168.161.3、192.168.161.4、192.168.161.5执行nacos/bin/startup.sh,在三台服务器上分别启动nacos。正常情况下,我们的集群节点就安装成功了。三个节点都可以提供服务,并且三个节点之间可以通信。通过浏览器访问nacos:http://ip:8848/nacos/可以正常的访问nacos服务。
注意:启动单机模式的用的是sh startup.sh -m standalone,而启动集群模式不需要-m standalone参数。
正常情况下,上面的步骤就可以安装成功了,三台服务器上的nacos可以对外提供服务,彼此间可以通信。但是,通常在生产环境下的服务器是多网卡的,nacos该如何正确的绑定网卡?
其网卡的选择配置和Spring Cloud系列配置是差不多的,可以参考《eureka集群多网卡环境ip设置》学习,但有些许的不同,下文会讲到。
查看我的服务器网卡:
使用ip addr命令查看linux主机的网卡。
因为较多的网络设备,导致我在后续安装过程出现问题。这里先卖个关子。
问题: 解决网卡获取的不是我们希望绑定的网卡的问题:当我们配置完成之后,使用startup.sh命令启动。发现集群节点列表中并没有任何记录。而且后台服务日志报错,内容如下:
解决方案一(较新的nacos版本):
针对我的网卡和期望ip,我的application.properties配置如下:
nacos.inetutils.ip-address=192.168.161.5
解决方案二(较旧的nacos版本):
针对我的网卡和期望ip,我的application.properties增加配置如下:
期望被忽略掉的网卡名称
nacos.inetutils.ignored-interfaces[0]=enp0s3
nacos.inetutils.ignored-interfaces[1]=docker0
期望匹配的网卡ip前缀
nacos.inetutils.preferred-networks[0]=192.168.161.
需要注意的是这里的inetutils配置的前缀是nacos,不是我们之前学过的spring.cloud,这点区别要注意,别配置错了
当以上工作都完成之后,我们通过浏览器分别访问nacos服务,看到如下界面。集群管理的节点列表里面已经有三各节点,ip分别是192.168.161.3:8848、192.168.161.4:8848、192.168.161.5:8848。
在完成nacos集群的配置之后,我们可以通过三个入口分别访问集群内的nacos服务,那下面的问题就是如何将三个入口转成一个入口,实现nacos server对外服务的负载均衡和高可用。
目前许多个人开发者写的博客或教程中的方法就是在三个nacos服务的前端加一个负载均衡器,如:nginx、haproxy。然后号称是生产级别的搭建方法,但这种方法是绝对不能用于生产的,因为你的nginx和haproxy是单点,一旦nginx挂了,整个服务就挂了。
nacos官网推荐的方法是使用虚拟ip的方法,如下:
这种虚拟ip的方法问题就是没有使用到负载均衡,访问的仍然是某一个节点的nacos服务,只不过形成了主从备份,提供了高可用。对于微服务量级不大的,这种就已经完全够用了。
那既可以提供高可用,又可以提供负载均衡的办法,可能有的朋友已经想到了,如下图:
我们就拿官网中推荐的方法(方案二),使用虚拟ip访问nacos集群的方式做个例子讲解一下。为什么不讲第三种?一般系统架构水平到了的人听懂这种方式就知道第三种方式怎么做,水平不到的人听了第三种仍然还是不懂。
在三台服务器上分别安装keepalived
yum install -y keepalived
在三台服务器上分别修改/etc/keepalived/keepalived.conf
vrrp_instance VI_1 {
state MASTER
interface enp0s8
virtual_router_id 51
priority 100
advert_int 1
authentication {
auth_type PASS
auth_pass 123456
}
virtual_ipaddress {
192.168.161.6
}
}
CentOS7必须开放防火墙配置,否则三台主机无法就虚拟ip的使用优先级通信,将都是MASTER,都配置虚拟ip。
firewall-cmd --direct --permanent --add-rule ipv4 filter INPUT 0 --protocol vrrp -j ACCEPT;
firewall-cmd --reload;
sudo systemctl restart keepalived.service
这时我们通过http://192.168.161.6:8848/nacos,访问的服务实际上是keepalived的MASTER节点192.168.161.3。如果我们把161.3的服务器停了,161.6的ip就漂移到161.4服务器上(按优先级)。总之可以保证192.168.161.6虚拟VIP提供的服务一直是可用的,除非nacos所有服务器节点都挂了。
本节就为大家介绍如何使用nacos作为服务注册中心。
也就是说我们使用Ribbon、OpenFeign作为远程调用的基础组件,然后将eureka服务注册中心替换为nacos。
因为nacos
属于Spring Cloud Alibaba
成员,为了规范相关版本与Spring Cloud、Spring Boot
版本之间的兼容性,我们在父项目pom
文件中引入spring-cloud-alibaba-dependencies
。
dependencyManagement的作用多次讲过了,通过dependencyManagement管理的dependency通常是多个子项目的父项目,我们通过import其pom信息,从而进行其子项目的版本号管理。一个父项目带多个子项目,父项目规定了子项目的版本号,从而个子项目之间的兼容性会更好。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR3</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- 在父项目中加入alibaba项目版本管理依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
在dependencyManagement中我们维护了三个核心依赖项目的版本,这个版本号之间关系是Spring Cloud Alibaba官方推荐的,能够体现更好的兼容性。spring-cloud-alibaba与spring-cloud和spring-boot之间的版本说明
Spring Cloud Version | Spring Cloud Alibaba Version | Spring Boot Version |
---|---|---|
Spring Cloud Hoxton.SR3 | 2.2.1.RELEASE | 2.2.5.RELEASE |
Spring Cloud Hoxton.RELEASE | 2.2.0.RELEASE | 2.2.X.RELEASE |
Spring Cloud Greenwich | 2.1.1.RELEASE | 2.1.X.RELEASE |
Spring Cloud Finchley | 2.0.1.RELEASE | 2.0.X.RELEASE |
Spring Cloud Edgware | 1.5.1.RELEASE | 1.5.X.RELEASE |
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
在application.yml中加入必要的服务注册中心信息配置我们上一篇文章中搭建的nacos的服务注册中心的地192.168.161.6:8848。(删掉eureka配置)
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.161.6:8848
加上EnableDiscoveryClient注解(去掉EnableEurekaClient注解),开启Spring Cloud的服务注册与发现功能。
在aservice-sms服务提供者和aservice-rbac服务调用者中将以上的三个动作完成,我们就成功的将eureka客户端替换为nacos-discovert客户端了。我们访问nacos服务,通过服务管理->服务列表,看到我们注册的服务已经在列表中。
服务注册成功了,剩下的就是服务之间实现远程调用的实现及测试了。Ribbon和OpenFeign现在已经做到了服务注册中心的无关性,也就是说:不论你用nacos、zookeeper、consul、eureka哪一个服务注册中心,OpenFeign和Ribbon的使用方式几乎都没有区别。
需要注意的是:我们使用openfeign进行远程服务调用,服务名称应该是和spring.applicatopn.name定义一致的。(这点与Eureka不同,eureka是将服务名称转成大写字母)
//@FeignClient("ASERVICE-SMS")
@FeignClient("aservice-sms")
public interface SmsService {
@PostMapping(value = "/sms/send")
AjaxResponse send(@RequestParam("phoneNo") String phoneNo,
@RequestParam("content") String content);
}
首先从最简单的信息开始看起:服务列表中aservice-rbac启动了一个实例,aservice-sms启动两个实例。并且所有实例都通过了nacos服务注册中心的健康检查。点击“详情”可以查看服务状态,以及服务所有启动实例的状态。
某些大型企业,为了满足异地容灾的需要,通常将应用部署在不同的机房。不同机房的服务器组通常被称为一个“集群”。但是nacos的集群与apollo(系列六会讲)有所不同:
对于注册在nacos server(集群A)上面的微服务实例,就是集群A的实例。同理,注册在nacos server (集群B)上面的微服务实例就是集群B的实例。所以nacos的“集群”信息是不需要我们手动添加的,微服务注册在哪个集群的nacos上,它逻辑上就属于那个集群。
nacos的微服务分组概念,有两层含义:
可以通过如下属性对微服务分组进行配置。
spring.cloud.nacos.discovery.group=
这就好像一些公司的人力分配,有些员工能力就是不行,领导也知道你不行,但是领导还是让他去领衔做一部分工作。因为这部分工作得有人做,不能所有工作全交给“原本行”的人去做,就把"原本行"的人压垮了。导致整个公司所有业务瘫痪。
配置项 | Key | 默认值 | 说明 |
---|---|---|---|
服务端地址 | spring.cloud.nacos.discovery.server-addr | 无 | Nacos Server 启动监听的ip地址和端口 |
服务名 | spring.cloud.nacos.discovery.service | ${spring.application.name} | 给当前的服务命名 |
服务分组 | spring.cloud.nacos.discovery.group | DEFAULT_GROUP | 设置服务所处的分组 |
权重 | 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.enpoint | UTF-8 | 地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址 |
是否集成Ribbon | ribbon.nacos.enabled | true | 一般都设置成true即可 |
是否开启NacosWatch | spring.cloud.nacos.discovery.watch.enabled | true | 可以设置成false来关闭watch |
nacos作为配置管理中心,实现的核心功能就是配置的统一管理,本节我们就以aservice-rbac为例读取nacos配置中心的配置数据,配置读取正确之后才能正确的启动aservice-rbac服务。
在aservice-rbac服务的pom文件中引入如下配置
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
新建配置文件bootstrap.yml,新增spring.cloud.nacos.config段配置,将服务指向正确的nacos服务端。该配置文件中只保留nacos相关的配置即可,其他的配置放到nacos中统一管理(配置的分类后文介绍)。
spring:
application:
name: aservice-rbac
cloud:
nacos:
discovery:
server-addr: 192.168.161.6:8848
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml #nacos配置文件后缀,下文配置发布的时候会用到。注意是yaml,不是yml
group: DHY_GROUP #配置分组,默认分组是DEFAULT_GROUP
这里需要格外注意:上面这些属性必须配置在bootstrap.yml或properties文件中,而不是application.yml中,config配置内容才能被正确加载。因为bootstrap.yml加载优先级高于application.yml,保证在应用一起动时就去加载配置,对于Spring 中一些自动装载类来说这很重要。
目前,我们把配置分为两类:
第二类配置,比如下面的这些配置:
server:
port: 8401
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
datasource:
url: jdbc:mysql://123.56.169.21:3306/xxx?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: xxx
password: xxx
driver-class-name: com.mysql.cj.jdbc.Driver
hikari:
minimum-idle: 5
maximum-pool-size: 15
auto-commit: true
idle-timeout: 30000
pool-name: RBACHikariCP
max-lifetime: 120000
connection-timeout: 30000
connection-test-query: SELECT 1
cloud:
inetutils:
preferredNetworks:
- 192.168
ignored-interfaces:
- .*VirtualBox.*
mybatis:
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
ribbon:
eager-load:
enabled: true
clients: aservice-sms
feign:
okhttp:
enabled: true
logging:
level:
com.dhy.cloud.aservice.rbac.feign.SmsService: debug
通过配置列表右侧的“+”按钮添加配置文件
点击“+”按钮之后,页面内容如下:
Data Id:该配置文件在nacos系统内的唯一标识,在 Nacos Spring Cloud 中,dataId的完整格式如:
${prefix}-${spring.profile.active}.${file-extension}
Group:同spring.cloud.nacos.config.group配置,界面填写的内容与项目中的配置二者一定要统一,否则无法正确读取配置,Group起到配置“隔离”的作用。
配置内容:将上文中分类完成的第二类配置,粘贴到里面。(在本地服务或项目中把这部分配置删掉)
最后将nacos配置发布、确定,如下图:
启动服务的时候,加上-Dspring.profiles.active=dev参数,这个参数是和DataId匹配的,如:
# 启动服务并加载`aservice-rbac-dev.yaml`配置文件
java -jar aservice-rbac.jar -Dspring.profiles.active=dev
服务启动后,我们可以验证一下aservice-rbac是否正确的读取到了nacos配置中心的配置:
可以看日志:
看看数据库连接池
因为我们的数据库配置是在nacos配置中心管理的,本地已经删除了。所以正确的初始化了数据库连接池,也能证明服务已经正确的读取到了nacos配置中心的配置。
后面的文章中还会为大家介绍配置动态刷新,可以进一步验证!
上一节给大家介绍了nacos客户端(也就是我们的业务微服务)在启动的时候,怎样实现配置从nacos配置中心加载。本节为大家介绍一下当配置发生变更的时候,如何动态的通知并刷新服务的配置数据。
配置管理平台 | Value | ConfigurationProperties |
---|---|---|
nacos | 需要结合RefreshScope才能生效 | 需要结合RefreshScope才能生效 |
apollo | 不需要结合RefreshScope就能生效(例外) | 需要结合RefreshScope才能生效 |
spring cloud config | 需要结合RefreshScope才能生效 | 需要结合RefreshScope才能生效 |
下面两个例子都可以将nacos配置"user.init.password"键对应的值热更新到password和defaultPwd对象上。这两个注解需要结合@RefreshScope
注解使用才能使配置动态更新生效。
@RefreshScope //这里需要加上RefreshScope注解
@ConfigurationProperties(prefix = "user.init")
public class User{
private String password;
}
下文中会针对这种@Value注解的方法为例进行讲解。
@RefreshScope //这里需要加上RefreshScope注解
public class Xxxxx{
@Value("${user.init.password}")
private String defaultPwd;
}
添加一个配置:user.init.password=12345678
在需要进行配置刷新的类上使用@RefreshScope,user.init.password
对应的配置对象defaultPwd
的值就具备了刷新的能力。
@Service
@RefreshScope
public class SysuserService {
@Value("${user.init.password}")
private String defaultPwd;
public void pwdreset(Integer userId){
if(userId == null){
throw new CustomException(CustomExceptionType.USER_INPUT_ERROR,
"重置密码必须带主键");
}else{
SysUser sysUser = sysUserMapper.selectByPrimaryKey(userId);
//String defaultPwd = dbLoadSysConfig.getConfigItem("user.init.password");
sysUser.setPassword(passwordEncoder.encode(defaultPwd));
sysUserMapper.updateByPrimaryKeySelective(sysUser);
smsService.send(sysUser.getPhone(),"您好,管理员已经将您的密码重置为" + defaultPwd);
}
}
}
使用postman向“/sysuser/pwd/reset”接口发送请求
端点如图所示
去nacos配置中心修改user.init.password的值为Abcd1234,再次通过postman发送请求
在以上的过程中,我们没有重启服务,就实现了配置在nacos中修改之后,服务自动更新配置所对应的对象的数据。
下面这张图是nacos官网讲解nacos数据模型的概念时给出的,用来理解nacos的隔离级别再好不过。
注意:学过apollo的同学不要把apollo的namespace和nacos的namespace搞混了,apollo的namespace是用于将多个服务或项目都需要使用的共有配置放到一个namespace中,方便多个项目公共加载使用。而nacos的namespace就是一个顶级的服务配置隔离级别。
其实还有一种隔离,是上面的这张图没有体现出来的,那就是:nacos可以增加多个用户(并为用户赋权)、在这些用户下可以建立namespace。不同用户建立的namespace里面的服务肯定是不能互相访问的,配置也是隔离的。
namespace没有一定的必须的隔离模式要求,你可以根据自己的情况进行隔离,比如:
根据自己的项目情况,公司项目、组织架构、外部客户等分组特征可以灵活决定namespace的隔离模式。下面为大家举两个常见的例子:
隔离级别 | 举例一 | 举例二 |
---|---|---|
namespace(一级) | 一套部署环境一个namespace,如:DEV开发环境;PRO生产环境 | 一个公司的一个部门建立一个namespace。如:开发一部,开发二部 |
group(二级) | 一个微服务综合项目一个组 | 一个微服务综合项目一个组 |
dataid/service(三级) | 微服务配置文件xxxx.yaml、yyyy.yaml | 微服务配置文件xxxx-dev.yaml、xxxx-pro.yaml来区分部署环境 |
group的分组模式:通常是一个微服务综合项目作为一个group,因为微服务模块之间需要互相调用,放在不同的组会产生隔离,无法彼此远程调用。
我们假设一个需求:为XX公司的“研发一部”建议一个namespace,该部门的所有项目都注册到这个namespace 下面,并且使用这个namespace下面的配置。
微服务在没有明确指定配置的情况下, 默认使用的是Public命名空间。如果需要明确使用自定义的命名空间namespace,可以通过以下配置来实现:
# 配置隔离的namespace
spring.cloud.nacos.config.namespace=fd96613a-2bad-4288-806d-0a7c2b265267
# 服务隔离的namespace
spring.cloud.nacos.discovery.namespace=fd96613a-2bad-4288-806d-0a7c2b265267
分组不需要在nacos管理界面中新建,只需要在nacos客户端配置即可。
# 服务隔离的分组group
spring.cloud.nacos.discovery.group=
# 配置隔离的分组group
spring.cloud.nacos.config.group=
nacos的配置共享的思路是:一个项目可以使用多个配置文件,既然一个项目或者子项目可以使用多个配置文件,那么配置共享是不是就简单了。方法就是:我们把公有配置单独抽取为一个配置文件,如下文中的:common-datasource.yaml。
准备工作:我们把原有的nacos上面的aservice-rbac-dev.yml配置文件拆分成两份。
现在配置文件被拆分成了两份,aservice-rbac服务该如何使用两份配置文件?不再使用默认的dataid规则加载配置文件,可以通过如下的方法加载多个配置文件:
spring:
cloud:
nacos:
#服务发现同样可以设置命名空间,组
discovery:
server-addr: 116.62.221.113:8848
namespace: BUGU
#配置中心
config:
server-addr: ${spring.cloud.nacos.discovery.server-addr}
file-extension: yaml
namespace: BUGU
#数据源配置不需要动态刷新
extension-configs:
- data-id: TestDataSource.yaml
group: BUGU_GROUP
refresh: false
#路由配置需要动态刷新
- data-id: TestGateWay.yaml
group: BUGU_GROUP
refresh: true
application:
name: BUGU-GATEWAY-DHY
图文详述Nacos配置中心使用:应用间配置共享、扩展配置文件加载优先级、新老版本差异
灰度发布是指在黑与白之间,能够平滑过渡的一种发布方式
。AB test就是一种灰度发布方式,让一部分用户继续用A,一部分用户开始用B,如果用户对B没有什么反对意见,那么逐步扩大范围,把所有用户都迁移到B上面来。灰度发布可以保证整体系统的稳定,在初始灰度的时候就可以发现、调整问题。
灰度发布就是让配置先在部分实例生效,如果效果理想全量发布到所有实例,如果效果不理想就可以放弃当前的“灰度发布配置”。
在nacos配置管理里面,与灰度发布有相同效果的发布方式被称为beta发布。其实二者的核心内涵并没有什么实质上的差别,下文取自百度百科:
beta发布就是发布一个公测版本,公测结果较好,就全量发布。公测结果不理想,就放弃Beta发布的版本。
aservice-rbac服务在192.168.161.3,192.168.161.4,192.168.161.5启动了三个实例。我们想把其中192.168.161.3,192.168.161.4实例的配置项"user.init.password"的值改为xxxxyyyy(即:Beta发布),192.168.161.5的配置不做更改。
因为这种测试方法我们之前的章节已经多次用过,这里就不截图详细说明了,测试方法如下:
出现以上结果,证明我们的Beta发布结果是正确的。
beta发布的配置可以进行回退,也可以全量发布
最近在使用Spring Cloud Alibaba这一套微服务解决方案,但是在服务注册的时候,网关死活找不到微服务地址,自己的微服务通过网关怎么也访问不到。
仔细一查才发现,网关去访问了一个莫名其妙的IP地址, 去Nacos服务详情去看,果然,我的微服务注册到Nacos的IP地址上也是这个地址, 然后我去我电脑查找这个IP地址,还真有这么一个地址,那么问题来了,Nacos为什么会随意找个本机IP地址然后注册上去?
Nacos注册中心是: https://github.com/alibaba/nacos
各个服务通过Nacos客户端将服务信息注册到Nacos上
当Nacos服务注册的IP默认选择出问题时,可以通过查阅对应的客户端文档,来选择配置不同的网卡或者IP
(参考org.springframework.cloud.alibaba.nacos.NacosDiscoveryProperties的配置
)
例如,使用了Spring cloud alibaba(官方文档)作为Nacos客户端, 服务默认获取了内网IP 192.168.1.21, 可以通过配置spring.cloud.inetutils.preferred-networks=10.34.12,使服务获取内网中前缀为10.34.12的IP
# 如果选择固定Ip注册可以配置
spring.cloud.nacos.discovery.ip = 10.2.11.11
spring.cloud.nacos.discovery.port = 9090
# 如果选择固定网卡配置项
spring.cloud.nacos.discovery.networkInterface = eth0
# 如果想更丰富的选择,可以使用spring cloud 的工具 InetUtils进行配置
# 具体说明可以自行检索: https://github.com/spring-cloud/spring-cloud-commons/blob/master/docs/src/main/asciidoc/spring-cloud-commons.adoc
spring.cloud.inetutils.default-hostname
spring.cloud.inetutils.default-ip-address
spring.cloud.inetutils.ignored-interfaces[0]=eth0 # 忽略网卡,eth0
spring.cloud.inetutils.ignored-interfaces=eth.* # 忽略网卡,eth.*,正则表达式
spring.cloud.inetutils.preferred-networks=10.34.12 # 选择符合前缀的IP作为服务注册IP
spring.cloud.inetutils.timeout-seconds
spring.cloud.inetutils.use-only-site-local-interfaces
spring.cloud.nacos.discovery.server-addr #Nacos Server 启动监听的ip地址和端口
spring.cloud.nacos.discovery.service #给当前的服务命名
spring.cloud.nacos.discovery.weight #取值范围 1 到 100,数值越大,权重越大
spring.cloud.nacos.discovery.network-interface #当IP未配置时,注册的IP为此网卡所对应的IP地址,如果此项也未配置,则默认取第一块网卡的地址
spring.cloud.nacos.discovery.ip # 优先级最高
spring.cloud.nacos.discovery.port # 默认情况下不用配置,会自动探测
spring.cloud.nacos.discovery.namespace # 常用场景之一是不同环境的注册的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。
spring.cloud.nacos.discovery.access-key # 当要上阿里云时,阿里云上面的一个云账号名
spring.cloud.nacos.discovery.secret-key # 当要上阿里云时,阿里云上面的一个云账号密码
spring.cloud.nacos.discovery.metadata #使用Map格式配置,用户可以根据自己的需要自定义一些和服务相关的元数据信息
spring.cloud.nacos.discovery.log-name # 日志文件名
spring.cloud.nacos.discovery.enpoint # 地域的某个服务的入口域名,通过此域名可以动态地拿到服务端地址
ribbon.nacos.enabled # 是否集成Ribbon 默认为true