zoukankan      html  css  js  c++  java
  • 分布式配置中心介绍--Spring Cloud学习第六天(非原创)

    文章大纲

    一、分布式配置中心是什么
    二、配置基本实现
    三、Spring Cloud Config服务端配置细节(一)
    四、Spring Cloud Config服务端配置细节(二)
    五、Spring Cloud Config客户端配置细节
    六、项目源码与参考资料下载
    七、参考文章

     

    一、分布式配置中心是什么

      随着我们的分布式项目越来越大,我们可能需要将配置文件抽取出来单独管理,Spring Cloud Config对这种需求提供了支持。Spring Cloud Config为分布式系统中的外部配置提供服务器和客户端支持。我们可以使用Config Server在所有环境中管理应用程序的外部属性,Config Server也称为分布式配置中心,本质上它就是一个独立的微服务应用,用来连接配置仓库并将获取到的配置信息提供给客户端使用;客户端就是我们的各个微服务应用,我们在客户端上指定配置中心的位置,客户端在启动的时候就会自动去从配置中心获取和加载配置信息。Spring Cloud Config可以与任何语言运行的应用程序一起使用。服务器存储后端的默认实现使用git,因此它轻松支持配置信息的版本管理,当然我们也可以使用Git客户端工具来管理配置信息。本文我们就先来看下Spring Cloud Config的一个基本使用。

    二、配置基本实现

    1. 构建配置中心

    首先我们来构建一个配置中心,方式很简单,创建一个普通的Spring Boot项目,叫做config-server,创建好之后,添加如下依赖:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <spring-cloud.version>Dalston.SR3</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    然后在入口类上添加@EnableConfigServer注解,表示开启配置中心服务端功能,如下:

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

    然后在application.properties中配置一下git仓库的信息,为了简单,我这里就不自己搭建git服务端了,直接使用GitHub(当然也可以使用码云),这里需要我首先在我的Github上创建一个名为scConfig的项目,创建好之后,再做如下配置:

    spring.application.name=config-server
    server.port=2007
    spring.cloud.config.server.git.uri=https://github.com/lenve/scConfig.git
    spring.cloud.config.server.git.search-paths=config-repo
    spring.cloud.config.server.git.username=username
    spring.cloud.config.server.git.password=password
    

    前两行配置的含义就不用我多说了,我说下后面四行配置的含义,如下:
    (1)uri表示配置中心所在仓库的位置
    (2)search-paths表示仓库下的子目录
    (3)username表示你的GitHub用户名
    (4)password表示你的GitHub密码
    做好这些之后我们的配置中心服务端就创建好了。

    2. 构建配置仓库

    接下来我们需要在github上设置好配置中心,首先我在本地找一个空文件夹,在该文件夹中创建一个文件夹叫config-repo,然后在config-repo中创建四个配置文件,如下:

     

    四个文件中的内容分别如下:

     

    OK,然后回到test目录下,依次执行如下命令将本地文件同步到Github仓库中,如下:

     

    如此之后,我们的配置文件就上传到GitHub上了。此时启动我们的配置中心,通过/{application}/{profile}/{label}就能访问到我们的配置文件了,其中application表示配置文件的名字,对应我们上面的配置文件就是app,profile表示环境,我们有dev、test、prod还有默认,label表示分支,默认我们都是放在master分支上,我们在浏览器上访问结果如下:

     

    OK,从这里我们看到了我们放在仓库中的配置文件。JSON中的name表示配置文件名application的部分,profiles表示环境部分,label表示分支,多了一个version,实际上就是我们GitHub上提交信息时产生的版本号,当我们访问成功后,我们还可以看到控制台打印了如下日志:

     

    实际上是配置中心通过git clone命令将配置文件在本地保存了一份,这样可以确保在git仓库挂掉的时候我们的应用还可以继续运行,此时我们断掉网络,再访问http://localhost:2007/app/prod/master,一样还可以拿到数据,此时的数据就是从本地获取的。

    3. 客户端配置

    服务端搞好了,接下来我们来看看怎么样在客户端使用。
    首先创建一个普通的Spring Boot工程config-client,创建成功之后添加如下依赖:

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <properties>
        <spring-cloud.version>Dalston.SR3</spring-cloud.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    

    然后创建bootstrap.properties文件,来获取配置信息,注意这些信息一定要放在bootstrap.properties文件中才有效,文件内容如下:

    spring.application.name=app
    spring.cloud.config.profile=dev
    spring.cloud.config.label=master
    spring.cloud.config.uri=http://localhost:2007/
    server.port=2008
    

    这里的name对应了配置文件中的application部分,profile对应了profile部分,label对应了label部分,uri则表示配置中心的地址。配置完成之后创建一个测试Controller,我们来看看效果:

    @RestController
    @RefreshScope
    public class HelloController {
        @Value("${sang}")
        String sang;
        @Autowired
        Environment env;
    
        @RequestMapping("/sang")
        public String sang() {
            return this.sang;
        }
        @RequestMapping("/sang2")
        public String sang2() {
            return env.getProperty("sang", "未定义");
        }
    }
    

    我们可以直接注入值,也可以通过Environment来获取值,访问结果如下:

     

    三、Spring Cloud Config服务端配置细节(一)

    我们先通过下面一张图来看看Config Server的一个大致工作过程:

     

    说明
    1.首先我们需要一个远程的Git仓库,自己学习可以直接用GitHub,在在实际生产环境中,需要自己搭建一个Git服务器,远程Git仓库的作用主要是用来保存我们的配置文件
    2.除了远程Git仓库之外,我们还需要一个本地Git仓库,每当Config Server访问远程Git仓库时,都会保存一份到本地,这样当远程仓库无法连接时,就直接使用本地存储的配置信息
    3.至于微服务A、微服务B则是我们具体的应用,这些应用在启动的时候会从Config Server中来加载相应的配置信息
    4.当微服务A/B尝试去从Config Server中加载配置信息的时候,Config Server会先通过git clone命令克隆一份配置文件保存到本地
    5.由于配置文件是存储在Git仓库中,所以配置文件天然的具备版本管理功能,Git中的Hook功能可以实时监控配置文件的修改

    Git URI中的占位符
    灵活的使用URI占位符,可以有效的减少我们的工作量。考虑这样一个问题,我有ServerA、ServerB两个服务,两个服务对应的配置文件的存储地址分别位于https://github.com/lenve/scConfig/sahttps://github.com/lenve/scConfig/sb,但是我的Config Server只有一个,那么当我的ServerA和ServerB连接上Config Server时,Config Server怎么知道去哪个地址下拿配置文件?这个时候就涉及到占位符的使用。
    在上篇文章中我们已经了解了Spring Cloud Config中的三种占位符,分别是{application}、{profile}和{label},这些占位符除了用来标识配置文件的规则,还可以用在Config Server中对Git仓库的URI配置,用在URI配置中时,这三个占位符的含义分别如下所示:

    1.{application}映射到客户端的 spring.application.name
    2.{profile}映射到客户端上的 spring.profiles.active
    3.{label}这是一个服务器端功能,标记”版本”的配置文件集

    此时,假设我不同环境下的配置文件分别放在下面这些目录下:

    https://github.com/lenve/scConfig/app/dev
    https://github.com/lenve/scConfig/app/prod
    https://github.com/lenve/scConfig/app/test  
    

    那么我的客户端文件这样配置:

    spring.application.name=app
    # dev根据具体情况来修改
    spring.cloud.config.profile=dev
    spring.cloud.config.label=master
    spring.cloud.config.uri=http://localhost:2007/
    server.port=2008
    

    然后Config Server按下面这种方式配置即可:

    spring.cloud.config.server.git.uri=https://github.com/lenve/scConfig.git
    spring.cloud.config.server.git.search-paths={application}/{profile}
    

    当然这种存储规划不一定最佳,这里只是给小伙伴们演示占位符的用法。

    默认情况下,Config Server 克隆下来的文件保存在C:Users<当前用户>AppDataLocalTemp目录下,我们可以通过如下配置来修改:

    spring.cloud.config.server.git.basedir=E:\111\
    

    健康监测
    默认情况下Spring Cloud Config会为配置中心服务端创建一个健康监测器,该检测器默认情况下是访问的仓库文件是{application}为app的配置文件,如果仓库中不存在这个文件,健康显示器就会显示仓库无法连接,此时我们有两种解决方案:1.仓库中添加相应的配置文件;2.重新指定检测的配置,重新指定方式如下:

    spring.cloud.config.server.health.repositories.check.name=app
    spring.cloud.config.server.health.repositories.check.label=master
    spring.cloud.config.server.health.repositories.check.profiles=dev
    

    此时,系统回去访问http://localhost:2007/app/dev/master地址,如果能够访问到,则显示仓库已连接,如下:

     

    安全保护
    开发环境中我们的配置中心肯定是不能随随便便被人访问的,我们可以加上适当的保护机制,由于微服务是构建在Spring Boot之上,所以整合Spring Security是最方便的方式。

    首先添加依赖:

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

    然后在application.properties中配置用户名密码:

    security.user.name=sang
    security.user.password=123
    

    最后在配置中心的客户端上配置用户名和密码即可,如下:

    spring.cloud.config.username=sang
    spring.cloud.config.password=123
    

    四、Spring Cloud Config服务端配置细节(二)

    1. 简介

    在微服务架构中,由于独立的服务个数众多,加上前期测试工作量大,一些原本由运维人员维护的敏感信息会被我们直接写在微服务中,以提高开发效率,但是这种明文存储方式显然是非常危险的,所以我们要对这些信息进行加密,而Spring Cloud Config则提供了对称加解密、非对称加解密的功能来帮助我们完成这一需求。OK,本文我们就来看看如何实现配置信息的加解密。

    2. 准备工作

    默认情况下我们的JRE中自带了JCE(Java Cryptography Extension),但是默认是一个有限长度的版本,我们这里需要一个不限长度的JCE,这个JCE我们可以直接百度然后在Oracle官网下载,下载之后解压,我们可以看到如下三个文件:

     

    我们需要将这里的两个jar包拷贝到我们的jdk安装目录下,我的是%JAVA_HOME%jrelibsecurity,覆盖该目录下原有的文件。

    如此之后,我们的准备工作就完成了。

    3. 对称加解密

    对称加解密比较简单,直接配置密钥就可以了,在我们前文创建出来的config-server中配置密钥,但是注意这个密钥需要配置在bootstrap.properties中,另外这里还有非常重要一点:Spring Cloud的Dalston.SR3和Dalston.SR2版本在这个问题上是有BUG的,如果用这两个版本在这里测试会没有效果,应该避开使用这两个版本,我这里使用的是Dalston.SR4版本,配置如下:

    encrypt.key=sang
    

    配置完成之后,启动我们的config-server工程,然后访问如下地址http://localhost:2007/encrypt/status,如果看到如下访问结果,表示环境搭建成功了:

     

    此时我们就可以通过第三方工具如POSTMAN、RestClient等来访问/encrypt和/decrypt接口,比如说我要给dev这个字符加密,方式如下(我这里以POSTMAN为例,注意是POST请求):

     

    解密方式如下:

     

    OK,拿到加密的字符串之后,我们就可以在配置文件中使用了,还是我们昨天的配置文件,这次我这样来写:

     
    image

    小伙伴们注意,配置文件的值如果是以{cipher}开头,表示该值是一个加密字符,配置中心config-server在获取到这个值之后会先对值进行解密,解密之后才会返回给客户端使用。

    4. 非对称加解密

    上文我们使用了对称加解密的方式来确保配置文件的安全性,如果使用非对称加解密的方式,我们的安全性将会得到进一步的提高。使用非对称加密的话需要我们先生成密钥对,生成密钥对可以直接使用jdk中自带的keytool工具,方式如下:

    keytool -genkeypair -alias config-server -keyalg RSA -keystore config-server.keystore
    

    执行效果如图:

     

    执行成功之后,会在命令执行目录下生成一个名为config-server.keystore的文件,将该文件拷贝到config-server的srcmain esources目录下,然后做如下配置:

    encrypt.key-store.location=config-server.keystore
    encrypt.key-store.alias=config-server
    encrypt.key-store.password=111111
    encrypt.key-store.secret=111111
    

    OK,如此之后我们的非对称加密就配置好了,测试方式和对称加密的测试方式一致,我这里就不再演示了。

    五、Spring Cloud Config客户端配置细节

    服务化配置中心

    在前面几篇关于Spring Cloud Config配置中心的文章中,我们在config-client中配置config-server地址的时候都是直接将地址写死,这种方式显然不够灵活,有的小伙伴可能已经想到了,这里我们可以结合eureka注册中心,然后在配置的时候直接使用服务名即可,OK,那我们对之前的项目稍加改造吧。

    config-server改造

    这里的改造都是非常简单的,服务端改造和客户端改造都是分三步走:1.添加依赖;2.添加注解;3.修改application.properties.

    首先我们在config-server中添加如下依赖:

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

    然后在config-server的入口类上添加@EnableDiscoveryClient注解,表示这是一个Eureka客户端,如下:

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

    最后在application.properties中配置eureka注册中心地址:

    eureka.client.service-url.defaultZone=http://localhost:1111/eureka/
    

    至此,我们的config-server就配置成功了。

    config-client改造

    config-client改造第一步也是先添加依赖,如下:

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

    然后入口类添加@EnableDiscoveryClient注解,如下:

    @SpringBootApplication
    @EnableDiscoveryClient
    public class ConfigClientApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ConfigClientApplication.class, args);
        }
    }
    

    最后修改配置文件,如下:

    spring.application.name=app
    # dev根据具体情况来修改
    spring.cloud.config.profile=dev
    spring.cloud.config.label=master
    eureka.client.service-url.defaultZone=http://localhost:1111/eureka/
    spring.cloud.config.discovery.enabled=true
    spring.cloud.config.discovery.service-id=config-server
    server.port=2008
    

    关于这个配置文件我说如下三点:

    1.eureka.client.service-url.defaultZone设置了注册中心的地址,将config-client注册到eureka注册中心中去
    2.spring.cloud.config.discovery.enabled表示开启通过服务名来访问config-server
    3.spring.cloud.config.discovery.service-id=config-server则表示config-server的服务名

    测试

    OK,经过以上的改造之后,此时我们分别启动eureka服务注册中心、config-server、config-client,然后访问http://localhost:1111,可以看到两个应用都已经注册成功了:

     

    然后继续测试config-client的/sang接口,结果如下:

     

    没问题。

    好了,服务化配置中心构建成功。

    失败快速响应

    不作任何额外配置的情况下,失败响应有点迟钝,举个简单的例子,关掉config-server,我们直接启动config-client,此时启动会报错,但是报错时间较晚,报错的时候系统已经打印了许多启动日志了,如果我们希望在启动失败时能够快速响应,方式很简单,config-client中添加如下配置即可:

    spring.cloud.config.fail-fast=true
    

    此时不启动config-server直接启动config-client依然会报错,但是我们看到报错时间较早,系统都没打印几条启动日志。

    重试机制

    如果由于网络抖动等原因导致config-client在启动时候访问config-server没有访问成功从而报错,这显然是不划算的,遇到这种情况我们希望config-client最好能重试几次,重试机制在这里也是受支持的,添加重试机制的方式很简单,引入如下两个依赖:

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

    引入依赖就OK了,不用做任何额外配置(当然要确保失败快速响应已开启),此时我们再尝试不启动config-server直接启动config-client,得到的启动日志如下:

     

    我们看到,config-client一共尝试了六次去访问config-server,六次都失败了才抛异常。

    和重试机制相关的配置有如下四个:

    # 配置重试次数,默认为6
    spring.cloud.config.retry.max-attempts=6
    # 间隔乘数,默认1.1
    spring.cloud.config.retry.multiplier=1.1
    # 初始重试间隔时间,默认1000ms
    spring.cloud.config.retry.initial-interval=1000
    # 最大间隔时间,默认2000ms
    spring.cloud.config.retry.max-interval=2000
    

    动态刷新配置

    有的时候,我动态的更新了Git仓库中的配置文件,那么我如何让我的config-client能够及时感知到呢?方式很简单,首先在config-client中添加如下依赖:

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

    该依赖中包含了/refresh端点的实现,我们将利用这个端点来刷新配置信息。然后需要在application.properties中配置忽略权限拦截:

    management.security.enabled=false
    

    OK,配置好之后,启动eureka注册中心,config-server和config-client,访问http://localhost:2008/sang,结果如下:

     

    此时我利用Git客户端工具,将app-dev.properties中的内容修改一下,修改成功之后,先用POST请求访问http://localhost:2008/refresh地址,结果如下:

     

    然后再访问http://localhost:2008/sang,结果如下:

     

    我们看到配置文件已经更新了。

    六、项目源码与参考资料下载

    链接:https://pan.baidu.com/s/1WgA85ExFsQQlU7Ek1Rvf6w
    提取码:p7qn

    七、参考文章

    https://www.cnblogs.com/lenve/p/7985943.html

  • 相关阅读:
    Hadoop生态圈-Azkaban实战之Command类型执行指定脚本
    Hadoop基础-MapReduce的排序
    Hadoop生态圈-Azkaban实战之Command类型多job工作流flow
    Hadoop生态圈-Azkaban部署实战
    SHELL脚本编程循环篇-until循环
    Hadoop生态圈-Kafka配置文件详解
    Hadoop生态圈-使用Kafka命令在Zookeeper中对应关系
    Hadoop生态圈-Kafka的旧API实现生产者-消费者
    Apache Kafka运维常用命令
    企业级Apache Kafka部署实战篇
  • 原文地址:https://www.cnblogs.com/WUXIAOCHANG/p/10933427.html
Copyright © 2011-2022 走看看