使用 Spring Cloud Config 我们可以实现配置的集中化管理,但 Spring Cloud Config 如果要实现配置的动态更新, 则需要借助 Spring Cloud Bus(参考 Spring Cloud(八):使用Spring Cloud Bus来实现配置动态更新)。 Nacos 不仅可作为服务注册中心,同时还可以作为配置的集中化管理中心,且其自身默认就支持动态更新,集成非常方便。

使用Spring Cloud Config我们能实现服务配置的集中化管理,在服务启动时从Config Server获取需要的配置属性。但如果在服务运行过程中,我们需要将某个配置属性进行修改,比如将验证码的失效时间从五分钟调整为十分钟,如何将这个更新在服务端不重启服务就能动态生效,是本文讨论的内容。

通过前面几篇文章的介绍,Spring Cloud微服务架构可通过Eureka实现服务注册与发现,通过Ribbon或Feign来实现服务间的负载均衡调用,通过Hystrix来为服务调用提供服务降级、熔断机制避免雪崩效应,通过Spring Cloud Config实现服务配置的集中化管理。微服务架构内部管理的基本组件差不多都已涵盖了,但是我们的服务最终是需要提供给客户端访问的,客户端如何来访问这些微服务,就需要引入一个叫服务网关的组件了。

Spring Cloud Config为微服务提供了集中化的配置管理,可以通过git仓库的形式来对各个服务的配置属性进行管理维护,在配置更新时,可通过消息总线的方式实现动态更新,而不需要重启服务。

架构

Spring Cloud Config属于CS架构,包括Config Server与Config Client, Config Server从配置存储库(可以是git,svn,jdbc数据库,或本地文件系统)获取配置属性,Config Client通过http请求对应的配置属性。如图

config-server

Config Server在客户端请求配置信息时,从git获取配置信息(可以配置为启动时即从git获取)返回给客户端,当配置发生更新时,可通过webhook的方式通知到Config Server,Config Server发出RefreshRemoteApplicationEvent 事件,通知客户端更新配置信息。

Config Server

搭建一个Config Server很简单。

  1. 首先pom.xml中引入依赖,
1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>

加入Eureka Client是使配置服务作为一个微服务注册到Eureka被其它微服务(作为Config Client)发现。

  1. 然后application.yml中添加配置,
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    spring:
    application:
    name: config-server

    cloud:
    config:
    server:
    git:
    uri: https://github.com/ronwxy/jboost-config
    searchPaths: '{application}' # 按应用名称分文件夹目录存储配置文件,只在应用名所在目录及顶层目录下寻找配置文件
    cloneOnStart: true # 启动时就获取配置,否则只有当客户端请求时才去获取配置
    basedir: D:\config #本地缓存路径
    forcePull: true # 在本地配置被污染(篡改)时, 强制拉取远程配置覆盖
    profile: ${spring.profiles.active:default}
    discovery:
    enabled: false

    server:
    port: 8888

    eureka:
    client:
    serviceUrl:
    defaultZone: http://localhost:8761/eureka/

上述配置使Config Server从github仓库获取配置信息,searchPaths: ‘{application}’ 可以将每个服务的配置属性文件放入仓库的同名文件夹下。 注意这里的引号是必须的,否则因为不符合yaml文件语法导致不生效。

定期刷新: spring.cloud.config.server.git.refreshRate 单位秒, 默认为0, 表示每次请求时,config server都会从git 仓库获取更新的配置。
本地缓存: 默认本地副本存在临时目录中,有些操作系统可能会定时清理临时目录,导致问题,设置配置的本地目录:spring.cloud.config.server.git.basedir

  1. 最后启动类上添加注解
1
2
3
4
5
6
7
8
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {

public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}

完成以上三步一个简单的Config Server就搭建完成了,启动项目,访问 http://localhost:8888/hello-service/dev 可获取到仓库 hello-service 目录下对应profile为dev的配置属性文件hello-service-dev.yml与默认配置文件(包括同目录下application.yml与仓库根目录下的application.yml, application-dev.yml配置文件)

通过url获取配置的访问方式:

  • /{application}/{profile}[/{label}]
  • /{application}-{profile}.yml
  • /{label}/{application}-{profile}.yml
  • /{application}-{profile}.properties
  • /{label}/{application}-{profile}.properties

其中 application是spring.config.name的值,profile可以是以逗号分隔的列表,label是git的分支,默认是master。

Config Server的高可用:

  1. 起多个实例,客户端配置spring.cloud.config.uri 以逗号隔开配多个uri
  2. 或将实例注册到服务注册中心

对于500,401等异常,客户端不会重试其它实例, 只在实例挂掉或连接超时时,才会重试其它实例

Config Client

客户端以springcloud-eureka-client项目为基础进行改造

  1. 在pom.xml中添加config相关依赖
1
2
3
4
5
6
7
8
 <dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

添加actuator可以暴露相关接口,如/env 来查看配置属性加载情况,springboot2中actuator默认只开放/info /health 两个接口,可通过如下配置放开(生产环境根据需要调整)

1
2
3
4
5
management:
endpoints:
web:
exposure:
include: "*"
  1. 添加bootstrap.yml配置文件
1
2
3
4
5
6
7
8
9
10
11
12
spring:
application:
name: hello-service

cloud:
config:
discovery:
enabled: true
serviceId: config-server
failfast: true # 在启动时如果连不上config server,则启动失败
name: ${spring.application.name}
profile: ${spring.profiles.active:default}

依次启动服务注册中心 springcloud-eureka, 配置管理服务 springcloud-config, 配置客户端 springcloud-eureka-client, 访问 http://localhost:8080/actuator/env 可看到配置客户端加载的配置信息。在配置客户端启动时,控制台也会打印从配置服务获取配置的相关信息,如

1
Located property source: OriginTrackedCompositePropertySource {name='configService', propertySources=[MapPropertySource {name='configClient'}, OriginTrackedMapPropertySource {name='https://github.com/ronwxy/jboost-config/hello-service/hello-service-dev.yml'}, OriginTrackedMapPropertySource {name='https://github.com/ronwxy/jboost-config/application-dev.yml'}, OriginTrackedMapPropertySource {name='https://github.com/ronwxy/jboost-config/hello-service/application.yml'}, OriginTrackedMapPropertySource {name='https://github.com/ronwxy/jboost-config/application.yml'}]}

这样,在客户端就可以通过 @ConfigurationProperties注解的属性类, @Value 注解,或Environment对象来访问相关属性,如

1
2
3
4
5
6
7
@Autowired
private Environment env;

env.getProperty("app")

@Value("${app}")
private String app;

客户端重试机制:

  1. 首先设置 spring.cloud.config.failfast=true
  2. 然后添加 spring-retry, spring-boot-starter-aop 依赖

默认进行6次重试,每次间隔一开始1s,然后每次1.1倍递增。如果要自定义,则通过spring.cloud.config.retry.* 配置参数, 或通过定义一个ID为configServerRetryInterceptor 的RetryOperationsInterceptor 类型的@Bean,可通过RetryInterceptorBuilder 来创建。

本文示例源码地址: https://github.com/ronwxy/springcloud-demos


认真生活,快乐分享 欢迎关注微信公众号:空山新雨的技术空间 ![微信公众号](/assets/qrcode-05.jpg)

上文介绍了服务如何通过Eureka实现注册,以及如何从Eureka获取已经注册的服务列表。那么拿到注册服务列表后, 如何进行服务调用?一个简单的实现是可以从被调用服务的实例列表中选择一个服务实例,通过其hostname(或IP),端口,及API的路径拼接成完整的url,通过http client来完成调用。但生产环境中,为了高性能、高可用等要素,服务的调用一般涉及负载均衡、故障转移、失败重试等实现,因此引入实现这些功能的客户端组件也成为了微服务架构中的必备要素。Spring Cloud中可通过Ribbon与Feign来实现服务间的调用。

本系列文章与示例均基于最新的Spring Cloud Hoxton版编写。

Spring Cloud 基于 Netflix 的几个开源项目进行了封装,提供包括服务注册与发现(Eureka),智能路由(Zuul),熔断器(Hystrix),客户端负载均衡(Ribbon)等在内的核心组件。

在微服务系统中,服务少则十几、几十个,多则上百、几百个(据悉 Netflix 的云平台上运行了500多个微服务),这些微服务通过相互调用来为用户提供功能。那么一个服务调用另一个服务是如何进行的,如何定位到另一个服务的地址?代码中写死,还是配置文件中配置?显然对于服务数量较多的系统,这两种方式先不说后续维护,光写起来就很痛苦。于是,对于微服务架构来说,服务的自动注册与发现就成为非常核心的功能,Eureka就是来负责实现这个功能的。

本系列文章与示例均基于最新的Spring Cloud Hoxton版编写。