一、配置中心作用

  在常规的开发中,每个微服务都包含代码和配置。其配置包含服务配置、各类开关和业务配置。如果系统结构中的微服务节点较少,那么常规的代码+配置的开发方式足以解决问题。当系统逐步迭代,其微服务会越来越复杂,慢慢演化成网状依赖结构,这个时候常规的代码+配置的开发方式就并不合适了,因为还要考虑整体系统的扩展性、伸缩性和耦合性等。这些问题中,配置的管理也是非常麻烦的。

  如果还是以常规开发形式管理配置,则要承担反复修改编译代码、重启系统、重新打包等风险。所以,一个可以集中管理,带有版本控制的配置中心应运而生。

  spring cloud config就是一个配置中心。其采用集中式管理每个微服务的配置信息,并使用GIT等版本仓库统一存储配置内容,实现版本化管理控制。微服务与配置中心使用rest方式交互来实现可扩展的配置服务。

  spring cloud config配置中心解决了微服务系统的配置中心化、配置版本控制、平台独立、语言独立等问题,其特性如下:

  • 提供服务端和客户端支持(spring cloud config server和spring cloud config client);
  • 集中式管理分布式环境中的配置信息;
  • 基于spring环境提供配置管理,与spring系列框架无缝结合;
  • 可用于任何语言开发环境;
  • 默认基于GIT仓库实现版本控制;

二、配置中心原理

            

三、配置中心应用

  3.1 搭建config server

  使用spring cloud config配置中心,首先要搭建一个配置中心服务,配置中心服务本身也是一个spring cloud微服务。需要在Eureka注册中心中发布订阅。需要依赖下述资源:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- spring cloud Eureka Client 启动器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>

  修改全局配置文件:

spring.application.name=spring-cloud-config-server
server.port=10801 # Git repository configure
# 远程仓库是用于集中管理各微服务配置文件的位置。配置文件需要通过GIT管理工具上传到GIT仓库中。配置文件命名有特有的规则,常见如下:
# applicationName-profile.properties
# applicationName-profile.yml
# applicationName是被管理配置文件的微服务服务命名,即spring.application.name
# profile是被管理配置文件的微服务环境,如开发环境的dev,测试环境的test等。如果未定义profile代表默认环境default。
# 配置Git远程仓库地址
spring.cloud.config.server.git.uri=https://github.com/kosamino/configs
# 如果远程仓库是公开的,不需要提供用户名和密码,如果是私有的,需要提供。
# spring.cloud.config.server.git.username=
# spring.cloud.config.server.git.password=

  提供启动类:

/**
* @EnableConfigServer - 开启配置中心,代表当前应用是一个配置中心服务端
* 应用会根据全局配置文件访问GIT远程仓库,并将远程仓库中的配置内容下载到本地。
*/
@SpringBootApplication
@EnableEurekaClient
@EnableConfigServer
public class ConfigServerApplication { public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}

  浏览器测试配置文件内容获取,从config server中获取配置文件有固定的访问方式。其格式为:

  http://config-server-ip:port/applicationName/profile[/label]

  • config-server-ip - 配置中心服务端IP
  • applicationName - 服务应用名,代表的是配置中心客户端服务命名,就是真正的服务应用中的spring.application.name值。也是配置文件的核心命名。
  • profile - 环境命名,代表的是配置中心客户端使用的具体环境,和之前课程中的多环境内容一致。也是配置文件的核心命名。根据applicationName和profile的含义,决定了GIT仓库中保存的配置文件命名是有要求的,配置文件命名要求是:applicationName[-profile].properties | applicationName[-profile].yml。提供固定的命名规则是用于配置中心客户端和服务端友好交互定义的。
  • label - 是GIT中的分支命名,默认为master,即主干。如果不是主干分支,必须提供分支命名。

  如:分支名称是abc,applicationName是testApp,环境是dev,那么请求路径是:http://config-server-ip:port/testApp/dev/abc

  从浏览器获取的配置文件内容结果是JSON格式的字符串。内容大致如下:

{
"name":"spring-cloud-config-client", // 服务名称
"profiles":["dev"], // 环境名称
"label":null, // 分支名称,默认为master
"version":"a600c404267f5341933ce02b3f62672ce5791b16", // 版本,由spring-cloud-config-server生成管理
"state":null,
// 配置具体内容,从spring-cloud-config-server中获取的配置一定包含default配置内容。
// 如:获取环境配置文件路径为http://config-server-ip:port/spring-cloud-config-client/dev,
// 那么不仅会返回master分支的spring-cloud-config-client-dev.properties配置文件内容,还会返回master分支的spring-cloud-config-client.properties配置内容。
"propertySources":[
{
"name":"https://gitee.com/kerwin_kim/test/spring-cloud-config-client-dev.properties", // 配置文件名,也是配置文件的远程GIT访问URL
"source": // 配置文件内容
{
"test.config.db.url":"jdbc:oracle:thin@localhost:1521:xe",
"test.config.db.password":"oracle-password",
"test.config.db.driver-class-name":"oracle.jdbc.driver.OracleDriver",
"test.config.db.username":"oracle"
}
},
{  //此处即为默认配置文件spring-cloud-config-client.properties
"name":"https://gitee.com/kerwin_kim/test/spring-cloud-config-client.properties",
"source":
{
"test.config.db.url":"jdbc:mysql://localhost:3306/test",
"test.config.db.password":"mysql-password",
"test.config.db.driver-class-name":"com.mysql.jdbc.Driver",
"test.config.db.username":"mysql"
}
}
]
}

  3.2 搭建config client

  被管理配置文件的微服务称为spring-cloud-config-client,其本身就是一个普通的微服务,只是配置文件由spring-cloud-config-server集中管理。这个微服务应用必须依赖spring-cloud-starter-config启动器资源,否则无法访问spring-cloud-config-server来获取远程配置内容。

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>

  spring-cloud-config-client应用必须提供当前服务的基础配置内容,如服务名称、服务端口、Eureka注册中心等,同时还必须配置访问哪一个spring-cloud-config-server。而当前应用的配置由被集中管理,所以全局配置文件命名修改为bootstrap.propertiesbootstrap配置文件也是spring-cloud的全局配置文件,其加载优先级高于application系列全局配置文件spring-cloud-config-client应用启动的时候先根据bootstrap配置来设置本地应用最基础的环境,再根据bootstrap中配置的远程spring-cloud-config-server信息来远程加载被集中管理的配置文件

  bootstrap.properties配置内容如下:

spring.application.name=spring-cloud-config-client
server.port=10803 # 配置config-client相关内容
# 开启配置中心搜索
spring.cloud.config.discovery.enabled=true
# 配置config-server配置中心的服务名称
spring.cloud.config.discovery.serviceId=spring-cloud-config-server
# 配置要从配置中心获取的配置文件具体环境,默认为default
spring.cloud.config.profile=dev
# 配置GIT中的分支名称,默认为master分支
spring.cloud.config.label=develop

四、热刷新client配置内容

  Config-client客户端服务应用,在启动的时候,会根据bootstrap配置内容远程访问config-server,获取当时的最新的配置内容。如果config-client运行过程中,GIT仓库中的配置内容发生变更,config-client不会自动的加载刷新配置内容。需要人为干预。

  • 重启服务,一定会刷新配置。重启服务代价太高。
  • 热刷新,服务不重启,不间断对外提供服务,而是重新加载配置内容,初始化应用环境。

  在工作中,不能因为配置的变更频繁重启各微服务,这样会严重影响系统的服务能力。那么在配置变化后,如何让微服务热刷新配置内容是一个必须解决的问题。对spring-cloud-config-server来说,GIT远程仓库中的配置内容是否发生变化都是无所谓的,因为当spring-cloud-config-client访问spring-cloud-config-server获取配置内容时,spring-cloud-config-server都会尝试访问GIT,获取最新的配置内容。

  而spring-cloud-config-client应用在启动后,需要提供不重启服务重新加载远程配置逻辑。这个热属性配置内容的功能需要依赖spring-boot-starter-actuator启动器来实现

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

  在actuator组件中,提供了refresh功能,这个功能就是刷新应用环境。但是spring-cloud默认关闭了这个功能的访问权限,需要在bootstrap配置文件中开启refresh访问权限

management.security.enabled=false

  actuator组件提供的refresh功能要求必须使用http协议访问,且必须是POST请求。方式任意(如postmam或者thymeleaf发送http请求)。如下通过thymeleaf刷新客户端示例:

  引入依赖:

<!-- thymeleaf启动器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

  新增Controller:

@Controller
public class DispatcherController { @GetMapping("/")
public String test(){
return "index";
}
}

  新增页面:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>热刷新应用配置</title>
<script type="text/javascript" src="jquery-1.9.1.js"></script>
<script type="text/javascript">
/*
* 注意: AJAX默认是不能做跨域访问的。当前的代码是为当前应用提供服务的。
* 如果需要跨域访问,建议使用HTTPClient技术实现。或其他技术实现。
*/
function refresh(){
var url = $("#urlValue").val();
$.ajax({
'url' : url,
'type': 'post',
'success' : function(data){
alert(data);
}
});
}
</script>
</head>
<body>
<center>
刷新工程:<input type="text" name="urlValue" id="urlValue"/>
<input type="button" value="刷新" onclick="refresh();">
</center>
</body>
</html>

  浏览器输入链接访问:http://ip:port/;再界面中输入/refresh点击“刷新”按钮即可,如图。

          

五、配置中心加密

  配置文件统一存储在GIT中,虽然增强了管理和版本控制,但是文件内容的安全性也成了问题。如果外部任意知道了GIT地址或spring-cloud-config-server的地址,那么配置文件的全部内容相当于对外完全开放。这个时候就需要提供配置内容加解密逻辑。将加密后的配置内容保存在GIT仓库中,在spring-cloud-config-client访问spring-cloud-config-server的时候,通过spring-cloud-config-server实现加密数据的解密,这样就可以保证配置内容的安全了。

  在spring-cloud架构中,Dalston.SR1版本可以正常提供加解密功能,而其他版本有BUG,无法提供加解密功能。使用加解密逻辑,需要在JDK/JRE环境中增加policy支持。需要在oracle官网上下载policy相关资源,地址为:

  http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

  将下载的两个policy相关jar包复制到$JAVA_HOME/lib/和$JAVA_HOME/jre/lib/目录中即可。当环境准备完毕后,可以通过下述地址测试spring-cloud-config-server的加解密环境是否生效:

  http://config-server-ip:port/encrypt/status

  5.1 对称加密

  使用相同的密钥(key)实现配置数据的加密和解密。在spring-cloud-config-server的全局配置文件中增加密钥配置:

# 对称加密:配置密钥内容,加密和解密都使用这个密钥
encrypt.key=test

  spring-cloud-config-server提供了对数据加密和解密的处理逻辑,要求必须使用POST请求方式,在请求体中直接传递要加解密的内容(json请求参数提交方式),spring-cloud-config-server会返回加解密后的结果。

  • 加密请求路径:http://config-server-ip:port/encrypt
  • 解密请求路径:http://config-server-ip:port/decrypt

  在GIT仓库中保存的密文数据使用前缀{cipher}表示数据为密文,如:

test.config.db.username={cipher}bb605c7e4bac3ae59ed83860a164b58b48fa1b08012ccaf49eb0b67825fefc33
test.config.db.password={cipher}7e97d20fe476b5268da4fea3dec63636f96e0dde4357acda4e614d33fcda1cfd

  这样spring-cloud-config-client通过spring-cloud-config-server获取配置数据的时候,spring-cloud-config-server会自动实现解密过程,并将解密后的结果返回给spring-cloud-config-client。

  同样采用thymeleaf,引入依赖spring-boot-starter-thymeleaf,然后添加Controller,

@Controller
public class DispatcherController { @GetMapping("/")
public String test(){
return "index";
}
}

  添加页面:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>加解密测试工具</title>
<script type="text/javascript" src="jquery-1.9.1.js"></script>
<script type="text/javascript">
function encrypt(){
var source = $("#sourceEncrypt").val();
$.ajax({
'url' : 'http://localhost:10801/encrypt',
'type': 'post',
'data': source,
'success' : function(data){
$("#singEncrypt").val(data);
}
});
}
function decrypt(){
var sing = $("#singDecrypt").val();
$.ajax({
'url' : 'http://localhost:10801/decrypt',
'type': 'post',
'data': sing,
'success' : function(data){
$("#sourceDecrypt").val(data);
}
});
}
</script>
</head>
<body>
<div style="padding-left: 100px; padding-right: 100px">
明文:<input type="text" name="urlValue" id="sourceEncrypt" style="width: 300px"/>
<br>
密文:<input type="text" name="urlValue" id="singEncrypt" style="width: 300px"/>
<input type="button" value="加密" onclick="encrypt();">
<hr>
密文:<input type="text" name="urlValue" id="singDecrypt" style="width: 300px"/>
<br>
明文:<input type="text" name="urlValue" id="sourceDecrypt" style="width: 300px"/>
<input type="button" value="解密" onclick="decrypt();">
</div>
</body>
</html>

  示例如图:

             

  5.2 非对称加密

  使用不同的密钥(key)实现配置数据的加密和解密。使用公钥加密数据,使用私钥解密数据
            

  JDK提供了java-keytool工具来生成密钥,生成的密钥信息是"keystore"文件。keytool工具使用方式如下:

keytool -genkeypair -alias "test" -keyalg "RSA" -keystore "test.keystore"
输入密钥库口令: 123456
再次输入新口令: 123456
您的名字与姓氏是什么?
[Unknown]: test
您的组织单位名称是什么?
[Unknown]: test
您的组织名称是什么?
[Unknown]: test
您所在的城市或区域名称是什么?
[Unknown]: beijing
您所在的省/市/自治区名称是什么?
[Unknown]: beijing
该单位的双字母国家/地区代码是什么?
[Unknown]: cn
CN=test, OU=test, O=test, L=beijing, ST=beijing, C=cn是否正确?
[否]: y 输入 <test> 的密钥口令test123
(如果和密钥库口令相同, 按回车):
再次输入新口令:test123

  将生成的密钥文件test.keystore保存到spring-cloud-config-server的classpath下(src/main/resources),并在全局配置文件中增加下述内容:

# 密钥文件保存路径
encrypt.key-store.location=classpath:test.keystore
# 密钥别名,此别名是公开的
encrypt.key-store.alias=test
# 密钥库口令
encrypt.key-store.password=123456
# 密钥口令
encrypt.key-store.secret=test123

  实现配置数据的加解密方式和对称加密一致。

六、配置中心的安全认证

  现在配置内容通过加解密的方式实现了安全保障,但是配置中心spring-cloud-config-server还是完全对外公开的。如果通过http协议地址:

  http://config-server-ip:port/applicationName/profile/label

  还是可以获取到配置文件内容,这对配置信息的安全保护还是不足。需要给spring-cloud-config-server提供用户安全认证,在这里使用spring-boot提供的security组件来使用HTTP Bastic用户安全认证

  在spring-cloud-config-server中增加新的依赖security:

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

  在spring-cloud-config-server全局配置文件中增加用户信息:

security.basic.enabled=true
security.user.name=test
security.user.password=123456

  这样就为spring-cloud-config-server提供了用户安全认证。

  在客户的bootstrap配置文件中增加下述内容,来实现spring-cloud-config-client访问spring-cloud-config-server的用户登录:

spring.cloud.config.username=test
spring.cloud.config.password=123456

七、多配置文件加载

  如果要想加载多个指定配置文件,而且此配置文件不是以spring.application.name命名规则命名的配置文件,则可以在config-client端配置文件:

# 加载多个配置文件,指定配置文件命名,不再使用spring.application.name查找配置文件,而是使用配置内容找指定的配置文件。常用。是配置在client端
spring.cloud.config.name=fileName1,fileName2

  如果要加载多目录下的配置文件,则需要在config-server端添加配置:

# 检索多个目录中的同名配置文件,常用于分目录管理多环境配置文件的情况下,如:dir1中保存default配置,dir2中保存dev配置,dir3中保存test配置。
# 配置文件命名规则不变,默认还是applicationName[-profile].properties。是配置在server端的。
spring.cloud.config.server.git.search-paths=dir1,dir2,dir3

八、 消息总线-BUS

  1、什么是Spring Cloud Bus

  Spring Cloud Bus集成了市面上常见的RabbitMQ和Kafka等消息代理。其会连接微服务系统中所有拥有Bus总线机制的节点,当有数据变更的时候,会通过消息中间件使用消息广播的方式通知所有的微服务节点同步更新数据。(如:微服务配置更新等)

  2 使用消息总线实现配置热刷新

  2.1 基于config client实现全局刷新

          

  这种实现方案在设计上并不是非常合适,比较刷新功能和某一个config client微服务耦合到了一起。可作为了解。

  实现Bus刷新功能需要在所有的config client端应用中增加spring-cloud-starter-bus-amqp依赖,这个依赖是消息总线集成的RabbitMQ消息同步组件。

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>

  在config client端的bootstrap配置文件中增加RabbitMQ相关配置:

spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=test
spring.rabbitmq.password=123456

  Bus消息总线会提供一个/bus/refresh服务来实现应用的热刷新。不再使用actuator来提供人刷新逻辑。/bus/refresh服务要求请求必须是post请求,可用任意技术实现

  这里要注意,虽然刷新服务的逻辑由Bus消息总线来提供,但是/bus/refresh服务默认还是关闭的,需要开启,在config client端的bootstrap配置文件中必须配置下述内容:

management.security.enabled=false

  2.2 基于config server实现全局刷新

            

  这种实现方案在设计上更加完美,将热刷新逻辑和具体的服务应用解耦。推荐使用。实现过程和2.1一致。需要config server和config client端都引入Bus消息总线组件。

  2.3 局部刷新服务

  使用Bus总线也可以实现部分服务热刷新。前文讲到的两种刷新实现方式都是全局热刷新,所有带有Bus消息总线组件且与同一个RabbitMQ连接的微服务应用都会执行热刷新逻辑。有些时候,热刷新只需要在一个微服务应用或一个微服务应用集群中执行,这个时候就需要使用局部刷新功能。

  局部热刷新的实现过程和全局热刷新一致,只是请求地址/bus/refresh需要提供一个GET请求参数,请求参数命名为destination,参数值是要刷新的微服务名称:端口[**]。如:

  微服务名: config-client

  微服务端口: 10802、10803、10804

  如果只热刷新微服务config-client:10802时,请求的路径为/bus/refresh?destination=config-client:10802

  如果需要刷新config-client微服务集群,则请求路径为/bus/refresh?destination=config-client:**

SpringCloud之Config配置中心+BUS消息总线原理及其配置的更多相关文章

  1. SpringCloud04 服务配置中心、消息总线、远程配置动态刷新

    1 环境说明 JDK:1.8 MAVENT:3.5 SpringBoot:2.0.5.RELEASE SpringCloud:Finchley.SR1 2 创建服务注册中心(Eureka服务端) 说明 ...

  2. [转]springcloud(九):配置中心和消息总线(配置中心终结版)

    https://www.cnblogs.com/ityouknow/p/6931958.html springcloud(九):配置中心和消息总线(配置中心终结版) 我们在springcloud(七) ...

  3. Spring Cloud(九):配置中心(消息总线)【Finchley 版】

    Spring Cloud(九):配置中心(消息总线)[Finchley 版]  发表于 2018-04-19 |  更新于 2018-05-07 |  我们在 Spring Cloud(七):配置中心 ...

  4. SpringCloud(八):springcloud-bus消息总线(刷新配置服务)

    Bus消息总线: 好了现在我们接着上一篇的随笔,继续来讲.上一篇我们讲到,我们如果要去更新所有微服务的配置,在不重启的情况下去更新配置,只能依靠spring cloud config了,但是,是我们要 ...

  5. springcloud(九):配置中心和消息总线(配置中心终结版)

    我们在springcloud(七):配置中心svn示例和refresh中讲到,如果需要客户端获取到最新的配置信息需要执行refresh,我们可以利用webhook的机制每次提交代码发送请求来刷新客户端 ...

  6. 微服务SpringCloud之配置中心和消息总线

    在微服务SpringCloud之Spring Cloud Config配置中心SVN博客中每个client刷新配置信息时需要post请求/actuator/refresh,但客户端越来越多时,,需要每 ...

  7. Spring Cloud(九):分布式配置中心和消息总线

    我们在Spring Cloud(七):使用SVN存储分布式配置中心文件和实现refresh中讲到,如果需要客户端获取到最新的配置信息需要执行refresh,我们可以利用webhook的机制每次提交代码 ...

  8. spring cloud深入学习(十)-----配置中心和消息总线(配置中心终结版)

    如果需要客户端获取到最新的配置信息需要执行refresh,我们可以利用webhook的机制每次提交代码发送请求来刷新客户端,当客户端越来越多的时候,需要每个客户端都执行一遍,这种方案就不太适合了.使用 ...

  9. Spring Cloud(十一)高可用的分布式配置中心 Spring Cloud Bus 消息总线集成(RabbitMQ)

    详见:https://www.w3cschool.cn/spring_cloud/spring_cloud-jl8a2ixp.html 上一篇文章,留了一个悬念,Config Client 实现配置的 ...

随机推荐

  1. mariadb升级

    官方文档升级:https://mariadb.com/kb/en/library/upgrading/ 1.备份原来的数据库和配置文件 # mysqldump -u root -p -A > a ...

  2. Zabbix部分监控指标

    MySQL请求流量带宽.MySQL响应流量带宽.CPU使用率.内存利用率.网卡流量等.

  3. Xena L23网络测试仪Valkyrie使用技巧100例:使用Xena官方在线演示设备 (编号00)

    需求# 1.新用户:没有硬件,想看看软件长什么样,好不好用,风格如何,怎么办? 2.代理商:没有硬件,想给客户Show一下Xena高大上的软件,怎么办? 3.老用户:邮件推送了新的软件版本,据说很多新 ...

  4. 神经网络与机器学习第3版学习笔记-第1章 Rosenblatt感知器

    神经网络与机器学习第3版学习笔记 -初学者的笔记,记录花时间思考的各种疑惑 本文主要阐述该书在数学推导上一笔带过的地方.参考学习,在流畅理解书本内容的同时,还能温顾学过的数学知识,达到事半功倍的效果. ...

  5. 第 20 课 go如何实现继承的 && 给引用模块起别名

    golang语言中没有继承,但是可以依靠组合来模拟继承和多态. package controllers import ( "encoding/json" md "gowe ...

  6. Vue Router路由管理器介绍

    参考博客:https://www.cnblogs.com/avon/p/5943008.html 安装介绍:Vue Router 版本说明 对于 TypeScript 用户来说,vue-router@ ...

  7. idea用maven创建web项目(详细)

    引用:http://blog.csdn.net/u010361662/article/details/50605099 欢迎添加微信

  8. input标签自动填充问题

    <input type='text' placeholder='手机号' /> <input type='text' placeholder='地址' /> <input ...

  9. TCP三次握手和四次挥手及wireshark抓取

    TCP的三次握手与四次挥手的详细介绍: 三次握手: 第一次握手(SYN=1, seq=x): 客户端发送客户端发送一个 TCP 的 SYN 标志位置1的,指明客户端打算连接的服务器的端口,以及初始序号 ...

  10. Android 卸载应用程序

    最近工作中接触Android应用实现卸载自身的逻辑,踩了一些坑之后整理下来.使用的方法是Intent.ACTION_DELETE,这里没有什么好说的. MainActivity.java : pack ...