假如说我们的配置从远程仓库获取失败了,那么该如何去处理呢?这里就要使用到 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 的情况下,能够刷新配置数据;最后的请求重试则保证了弱网环境下服务的可用性,在实际生产项目中,这三个基本上也都是必配的,大家需要认真掌握。

项目地址

github