假如说我们的配置从远程仓库获取失败了,那么该如何去处理呢?这里就要使用到 Spring Cloud Config 为我们提的动态刷新重试功能了,Spring Cloud Config 是服务化的。那么什么是服务化呢?
服务化
我们在前面的配置中,当 Config Client 需要从 Config Server 上获取配置数据时,我们都是直接在 Config Client 的配置文件中写上 Config Server 的地址,类似下面这种架构:
这种写法相当于将 Config Client 和 Config Server 绑定死了,以后 Config Server 的地址不能变,Config Server 也不能挂,否则 Config Client 就获取不到信息了,而且这种方式也破坏了我们微服务的整体架构,即服务之间互相调用,获取对方的信息都是去服务注册中心上获取,所以我们要对这种结构进行改造,改造成下面这种结构:
当 Config Server 启动时,将自己注册到服务注册中心 Eureka 上,所有 Config Client 都从 Eureka 上去获取 Config Server 的信息,这样我们就成功将 Config Server 和 Config Client 解耦了,Eureka 在这里依然扮演了数据中心的角色。
那么下面我们来演示如何服务化,大家可以根据上一篇的例子进行改造。当然也可以再创建一个项目来实现。这里我选择重新创建来带着大家来搭建。
首先我们依然是创建一个cloudConfig-fwh普通maven工程来作为父工程。然后再从cloudConfig-fwh中创建一个普通的文件夹configRepo来存放github配置文件,然后再分别创建eureka、config_server、config_client。
创建好后,项目结构如下:
然后我们分别将config_client 和 config_server 注册到eureka实例上。
我们访问localhost:7000
发现已经注册上去了。
那么我们还需要对Config Client配置,这里我们在bootstrap.yml中配置,bootstrap.yml优先级比application.yml高,spring cloud config 优先配置都会放在这里:
bootstrap.yml 配置如下:
spring:
application:
name: config-server
# 本地配置
# profiles:
# active: native
cloud:
config:
profile: dev
label: master
discovery:
service-id: config-server3
enabled: true
server:
port: 8002
eureka:
client:
service-url:
defaultZone: http://localhost:7000/eureka/
这里新增的两个配置我说一下,其中discovery.service-id
代替了原来的cloud.config.uri
原来的uri需要写很长。而且如果ip地址端口号发生了变化,那么还需要去Config Server去修改,这里使用了service-id完美了解决了这个问题。通过service-id去eureka中心寻找Config Server的实例。discovery.enabled=true
是开启通过eureka来获取Config Server。
注意这里有一个小坑。就是这个spring.application.name的名称是你在github仓库的配置文件的前缀如下图:
这里取config-server就可以了。
配置好了后,我们访问http://localhost:8002/love
访问结果如下:
这样就访问成功了,说明我们的配置没有问题。下面我们来说一下动态刷新。
动态刷新
接下来我们再来看一下配置文件动态刷新的问题,当 Git 仓库中配置文件发生改变后,如果我们刷新 Config Server 中的请求地址,会发现数据也跟着变化了,即 Config Server 是能够及时感知到配置文件的变化的,但是这种感知却不能够传递到 Config Client 中去,即 Config Client 是无法及时感知到配置文件的变化的,默认情况下,只有 Config Client 重启,才能够加载到最新的配置文件数据,如何让 Config Client 也能动态刷新配置数据呢?
我们只需要在Config Client 中加入如下依赖就能动态刷新配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
添加完成后我们还需要对refresh接口暴露,这里注意,除了G版本的Cloud需要额外手动的暴露refresh接口外,其它版本的Cloud不用配置下面这段配置来进行手动暴露
management:
endpoints:
web:
exposure:
include: 'refresh'
这里配置好了后,我们对HelloController增加一个注解@RefreshScope
当调用refresh
接口当时候动态刷新:
@RefreshScope
@RestController
public class HelloController {
@Value("${love}")
String love;
@GetMapping("/love")
public String name() {
return love;
}
}
配置好了后,我们重启Config Client项目,然后可以看到idea的控制台/actuator/refresh
接口已经暴露出来了。
这个接口用来动态刷新配置文件。
当然配置好了这个动态刷新接口,我们肯定要访问来测试下。接口是否正常。
我们访问http://localhost:8002/actuator/refresh
注意这里使用post请求访问,如果如下图一样就说明接口正常:
但细心的人可能这里会发现一个问题,不重启Config Client的情况下,也能实现动态刷新配置,但是所有的微服务都要一个个的去发送/actuator/refresh
接口请求,很麻烦,那么有什么简便的方式呢?肯定是有的下面我会介绍。
请求失败重试
请求失败了肯定要重试啊,不可能失败了,就让它一直失败。这肯定是不行的。细心的朋友看过我之前的文章的话,我是讲了如何失败重试的,比如网络的波动,当网络质量很差的情况下,就会导致服务调用的失败。那么我们就要做到请求失败了,就要重试。
要实现失败重试也是非常简单的,之前看过我文章的朋友,肯定知道这里需要加两个依赖:
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
加上这个依赖后,我们需要在Config Client 的bootstrap.yml中加入如下配置:
fail-fast: true
这个配置的意思是失败快速响应,在默认情况下 我们的Config Client 去访问Config Server 失败时候,并不会马上报错
而是要等到使用到Config Server 的某个数据
的时候才会报错
,通俗的意思就是我们之前不是有个love变量吗?如果这个love变量并不存在,而我们的Config Client又在调用使用的话,那么就会报错并抛出异常。所以当我们的Config Client 访问 Config Server 失败的时候,就要开启快速响应,这里可以是失败重试,也可以抛出自定义异常信息。
添加完这个配置之后,为了演示执行效果,接下来我们再做一点点修改,由于目前我们的 Config Server 是有安全认证的,Config Client 必须要有用户名密码才能访问到 Config Server 中的数据。我们暂时先注释掉 Config Client 中访问 Config Server 的用户名密码,即如下两行:
#spring:
# cloud:
# config:
# username: jishu
# password: 123456
这里的username 和 password 是在Config Server 中配置的Security的账户密码信息,这里我们注释掉后,重启Config Client 项目,我们来看下失败重试的效果:
可以看到,一共发了6次请求,第一失败后,还继续重试了5次,这就是默认的请求策略,我们可以配置请求策略:
spring:
cloud:
config:
retry:
initial-interval: 1000
multiplier: 1.1
max-interval: 2000
这四个配置解释如下:
- max-attempts 表示最大请求次数,默认值为 6 ,就是大家在上图看到的情况
- initial-interval 表示请求重试的初始时间间隔
- multiplier 表示时间的间隔乘数,由于网络抖动一般都是有规律的,为了防止请求重试时连续的冲突,我们需要一个时间间隔乘数,这里我设置了间隔乘数为 1.2 ,表示第一次重试间隔时间为 1 s,第二次间隔时间为 1.2 秒,第三次间隔时间为 1.44 秒…
- max-interval 表示重试的最大间隔时间
开启了请求重试机制之后,即使在弱网环境下,我们也能有效保证服务的可用性。
总结
本文主要向大家介绍了分布式配置中心 Spring Cloud Config 中三个常见的问题,服务化、配置数据动态刷新以及请求失败重试。服务化降低了 Config Server 和 Config Client 之间的耦合度,使我们的项目架构更加规范;动态刷新则让我们在不重启 Config Client 的情况下,能够刷新配置数据;最后的请求重试则保证了弱网环境下服务的可用性,在实际生产项目中,这三个基本上也都是必配的,大家需要认真掌握。