分布式配置中心解决方案

国内:

  • 360: QConf
  • 淘宝:diamond
  • 百度:disconf

国外:

  • Apache Commons Configuration
  • owner
  • cfg4j

但是都不如 Spring Cloud Config 强大,因为它与 Spring 家族融合最好。


Spring Cloud Config 简介

Spring Cloud Config 是一个分布式系统配置管理的解决方案。它包含了 Client 和 Server。配置文件放在 Server 端,通过接口的形式提供给 Client。

Spring Cloud Config 主要功能:

  • 集中管理各个环境、各个微服务的配置文件
  • 提供服务端和客户端的支持
  • 配置文件修改后,可以快速生效
  • 配置文件通过 Git/SVn 进行管理,天然支持版本回退功能
  • 支持高并发查询、同时支持多种开发语言

Spring Cloud Config 学习

Spring Cloud Config 准备工作

准备工作主要是给 Github 上提交数据。

  1. 首先在本地创建好相应的配置文件,我们在本地新建了一个 configRepo 文件夹,里面的单个文件夹代表一个服微务,服务文件夹里面是测试上传的 .properties 文件。
  2. 提交到 Github 上

ConfigServer 搭建

ConfigServer 从 GitHub 上加载数据的配置文件,加载到配置文件之后,以接口的形式提供给 ConfigClient。

  1. 首先创建一个 ConfigServer 工程,创建时添加 ConfigServer 依赖。
  2. 在启动类上添加 @EnableConfigServer 注解,开启配置服务器功能。
  3. 配置 application.yml,配置仓库的基本信息。
  4. 访问测试: http://localhost:8081/client1/dev/main 或者 http://localhost:8081/client1-dev.yml 或者 http://localhost:8081/client1-dev.properties ,控制台中会显示,在 github 中会克隆一份文件到本地的临时目录中。
  5. 启动项目后,就可以访问配置文件了。

访问地址有规则:

  • /{application}/{profile}/[{label}]
  • /{application}-{profile}.yml
  • /{application}-{profile}.properties
  • /{label}/{application}-{profile}.yml
  • /{label}/{application}-{profile}.properties
application 表示配置文件名
profile 表示配置文件 profile,例如 dev、test、prod
label 表示 git 分支,参数可选,默认是 master

接下来可以修改配置文件,并且重新提交到 Github,此时,刷新 ConfigServer 接口,就可以及时看到最新的配置内容。


ConfigClient 搭建

  • 首先创建一个 spring boot 项目,添加 ConfigClient 依赖。
  • 创建成功后,在 resources 目录下,添加 bootstrap.yml 配置文件。
  • 配置 bootstrap.yml。
  • 接下来创建一个 HelloController 进行测试。

ConfigServer 简单配置

使用占位符灵活控制查询目录:

  • 修改 config-server 配置文件,将写死的 client1 改为 {application}。这里的 {application} 占位符,表示链接上来的 client1 的 spring.application.name 属性的值。
  • 可以使用 {profile} 表示 client 的 spring.cloud.config.profile,也可以使用 {label} 表示 client 的 spring.cloud.config.label

虽然在实际开发中,配置文件一般都是放在 git 仓库中,但是 config-server 也支持将配置文件放在 classpath 下。(仅作为了解,实际开发不推荐)

  • 将配置好的文件复制到 resources 目录下。
  • 在 application.yml 下添加配置 spring.profiles.active=native,表示让 config-server 从 classpath 下查找配置,而不是去 Git 仓库上查找。
  • 随便修改一下配置文件,然后重启 config-client、config-server 服务,重新访问测试接口返回。

Config 配置文件加密和解密

常见的加密方案

不可逆加密

不可逆加密就是理论上无法根据加密后的密文推算出明文,像加密的框架 Shiro(MD5、SHA) 、Spring Security 都是采用这种方式,一般使用在密码加密上,常见的算法:

  • MD5 消息摘要算法
  • SHA 安全散列算法

可逆加密

可逆加密就是可以根据加密后的密文推断出明文的加密方式,可逆加密一般又分为两种:

对称加密
对称加密指的是加密的密钥和解密的密钥是一样的,常见的算法并随顺序强度逐渐升级:

  • des
  • 3des
  • aes

首先下载不限长度的 JCE:https://www.oracle.com/java/technologies/javase-jce8-downloads.html

macOS 中 Java 安装包地址:/Library/Java/JavaVirtualMachines/jdk1.8.0_361.jdk/Contents/Home/jre/lib/security/policy

  • 将两个.jar 包复制到 jre 目录下。
  • 然后在 config-server/resources 目录下,添加 bootstrap.yml 配置文件,并且配置密钥。
  • 启动 config-server 后,访问 http://localhost:8081/encrypt/status , 查看密钥配置是否成功,返回 200 即为成功。
  • 然后使用测试工具 Apifox 中 POST 请求 http://localhost:8081/encrypt ,这个接口请求的方式是 post,请求的 body 应该以 json 的形式写到 raw 里面,可以对一段明文进行加密,把加密后的明文存储到 Git 仓库。
  • 存储时候注意需要在密文前添加 {cipher} 前缀,表示这一段数据是密文,而不是一段普通的字符串。

非对称加密
非对称加密指的是加密的密钥和解密的密钥不一样,加密的称之为公钥,可以告诉任何人,解密的称之为私钥,只能自己知道,比如 Github 的验证、支付宝的支付开发,一对多的场景一般都使用用非对称加密。常见的算法:

  • RSA
1. 非对称加密我们首先需要生成一个密钥对。
2. 在命令行执行命令,生成 keystore: keytool -genkeypair -alias "config-server" -keyalg RSA -keystore "/Users/sihai/Object/Spring Cloud/Eureka/config-server.keystore" 3. 命令执行完成后,拷贝生成的 keystore 文件到 config-server 的 resources 目录下。
4. 然后在 config-server 的 bootstrap.yml 中添加非对称加密配置。
5. 注意,还需要在 pom.xml 的 build 节点中,添加配置,防止 keystore 被过滤掉。
6. 启动 config-server 后,访问 http://localhost:8081/encrypt/status , 查看密钥配置是否成功,返回 200 即为成功。
7. 然后使用测试工具 Apifox 中 POST 请求 http://localhost:8081/encrypt ,这个接口请求的方式是 post,请求的 body 应该以 json 的形式写到 raw 里面,可以对一段明文进行加密,把加密后的明文存储到 Git 仓库。
8. 存储时候注意需要在密文前添加 {cipher} 前缀,表示这一段数据是密文,而不是一段普通的字符串。

configServer 安全管理

防止用户可以直接访问 config-server 看到配置文件内容,我们可以用 spring security 来保护 config-server 接口。

  1. 既然我们需要使用 spring security,那么就需要先在 config-server 中添加其依赖。只要添加了依赖,你的接口就已经会被保护。
  2. 由于 security 的用户名密码不好记,所以我们可以分别在 config-server、config-client 配置文件中自定义,固定用户名密码。

Config 配置服务化

前面的配置都是直接在 config-client 中写死了 config-server 的地址,我们需要注册到 eureka 中,相互调用地址。

  • 启动 Eureka。
  • 在 client、server 中添加 Eureka 依赖。
  • 在 application.yml 配置文件中配置注册信息,为了 config-client 不再直接写死 config-server 的地址,同时注释掉 client 中 config.uri 的地址。
    注意:加入了 eureka client 之后,启动 config-server 可能会报错,这个时候,我们可以重新生成另一个 jks 格式的密钥。
keytool -genkeypair -alias "mytestkey" -keyalg RSA -keypass 111 -keystore "/Users/sihai/Object/Spring Cloud/Eureka/config-server.jks" -storepass 111

然后复制到 config-server 下的 resources 目录下,修改配置文件,修改 location、alias 配置。同时需要修改 pom.xml 过滤条件。


config 配置动态刷新

当配置文件发生了改变之后,config-server 可以及时的感知到了变化,但是 config-client 不可以及时的感知到,在默认情况下,config-client 只有重启才能加载到最新的配置文件,很不方便,我们需要做到不重启 config-client 也可以重新加载到配置文件。

  1. 首先给 config-client 添加 actuator 依赖。
  2. 添加配置,使 refresh 端点暴露出来。
  3. 再给 config-client 使用了配置文件的地方加上 @RefreshScope 注解,这样的话,当配置发生了改变之后,只需要调用 refresh 端点,config-client 中的配置就可以实现自动刷新。
  4. 重启 config-client,只要配置文件发生改变,访问 POST 请求的 http://localhost:8082/actuator/refresh ,调用一下这个端点后,重新请求 http://localhost:8082/hello ,就会自动刷新过来。

Config 解决请求发送失败重试

config-client 在调用 config-server 时,也一样有可能会发生请求失败的问题。这个时候,我们可以配置一个请求重试的功能。

  1. 需要给 config-client 添加重试功能,只需要添加 retry、aop 即可。
  2. 添加了 retry 之后,这个服务就已经具备了重试功能。
  3. 然后需要修改配置,开启失败快速响应。
  4. 如果注释掉配置文件中的 security 用户名密码,重启 config-client,此时加载配置的失败,就会自动重试。
  5. 也可以通过 config.retry 中的配置,来保证服务的可用性。