分布式配置中心-Config

一、常规的配置设置方式

  • Hardcode:写死在代码之中,每次修改需要发布修改代码,并且配置零散的存放在程序各处
  • 配置文件:从代码中提到application.yml和bootstrap.yml文件中,虽然修改后依旧要重新发布程序,但是配置被集中管理了
  • 环境变量:一般情况下是通过程序启动参数 和 系统层面的环境变量实现
  • 数据库(缓存)存储:将参数存放到数据库中使用,这种方式会增加数据库的压力

1、传统配置管理的缺点

  • 格式不统一:传统的配置文件格式不统一,SpringBoot的有properties和yml,spring的用xml配置,再老一点的还有使用json的
  • 没有版本管理:使用配置文件还有git和svn能管理一下,存到数据库中的 真的是改掉再也变不回来了。
  • 基于静态配置:修改、发布的流程繁琐,每次变动都需要在发布
  • 分布零散:hardcode方式直接散落在代码中,配置文件的方式好一点,但是随之时代的进步,在分布式的架构中配置文件的方式力不从心了,每一个模块都有大量的配置

二、分布式配置中心——Config

Config作为SpringCloud官方指定产品,必然有独到之处,在配置管理方面主要提供了三大功能

  • 统一配置:提供了一个中心化的配置方案,将各个项目中的配置内容集中在Config Server一端
  • 环境隔离:Config Server提供了多种环境隔离机制,Client可以根据自身所处的项目环境(比如生产环境、测试环境)加载对应的配置文件
  • 动态刷新:支持运行期改变配置属性
    除此之外,还有加密解密、定向推送等功能

1、Config的配置文件命名规则

  • application:服务的名字
  • profile:环境名称
  • label:对应git上不同的分支,默认为:master(程序的git版本与之对应,可以用于配置文件的版本控制)

规则1:{application}-{profile}.yml或{application}-{profile}.properties
示例:order-dev.yml 订单服务开发环境的配置文件

规则2:/{label}/{application}-{profile}.yml或/{label}/{application}-{profile}.properties
示例:/master/order-dev.yml 主分支下的订单服务开发环境的配置文件

规则3:{application}/{profile}[/{label}]

2、config小demo

(1)前期准备
1)创建一个git项目

在git、码云或者github上创建一个新的项目,专门用来存放配置文件,我这里命名为:config-repo

2)在git上创建配置文件

在config-repo中创建一个文件名为config-consumer-dev.yml

info: 
    profile: dev
    
name: Saul
words: 'God bless me'

然后提交文件,再创建一个配置文件,文件名为config-consumer-prod.yml

info: 
    profile: prod
    
name: Paul
words: 'God bless you'
(2)服务端代码
1)创建一个config-server(配置中心的服务模块)模块,修改配置文件
<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
</dependencies>
2)修改配置文件
@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication{
    public static void main(String[] args){
        new SpringApplicationBuilder(ConfigServerApplication.class)
            .web(WebApplicationType.SERVLET)
            .run(args);
    }
}
3)创建配置文件application.yml
server: 
    port: 60000

spring: 
    application: 
        name: config-server
    cloud:
        config: 
            server:
                #强制重载配置,把远端上的配置覆盖掉
                overrides:
                    #忽略远端上的test属性,使用这里的test值
                    test: mytest
                git:
                    #git地址
                    uri: https://github.com/xxxx/config-repo.git
                    #git登录名
                    username: 敲代码的旺财
                    #git密码
                    password: 真帅
                    #配置文件在git下的目录,可以配置多个,主要用于区分开项目
                    #search-paths: test, mall
                    #强制拉取
                    force-pull: true
4)运行模块进行测试

发送一个git请求到 http://localhost:60000/config-consumer/dev

  • http://localhost:60000/:这部分是服务地址
  • config-consumer/dev:这部分是配置的文件名

可以多尝试几种访问:config会自动转换格式,返回我们对应的格式

  • http://localhost:60000/config-consumer-dev.yml
  • http://localhost:60000/config-consumer/dev.properties
  • http://localhost:60000/config-consumer/dev.json
(3)客户端代码
1)创建一个config-client模块,修改配置文件
<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>
    <!-- 配置中心需要他暴露端口,提供动态拉取参数的能力 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-cloud-starter-actuator</artifactId>
    </dependency>
</dependencies>
2)修改配置文件
@SpringBootApplication
public class ConfigClientApplication{
    public static void main(String[] args){
        new SpringApplicationBuilder(ConfigClientApplication.class)
            .web(WebApplicationType.SERVLET)
            .run(args);
    }
}
3)创建一个Controller
@RestController
//spring的注解,可以重新初始化当前对象,并且会完全的重新注入对象
@RefreshScope
public class Controller{
    @Value("${name}")
    public String name;
    @Value("${myWords}")
    public String words;
    
    @GetMapping("/name")
    public String getName(){
        return name;
    }
    
    @GetMapping("/words")
    public String getWords(){
        return words;
    }
}
4)创建配置文件application.yml
server: 
    port: 61000
    
#从配置中心获取words属性
myWords: ${words}

spring: 
    application: 
        name: config-client
    cloud:
        config: 
            #配置中心地址
            uri: http://localhost:60000
            #加载的配置文件的环境(这里一般不是写死的 而是通过启动参数,或者系统环境变量来配置)
            profile: prod
            label: master
            #指定配置文件中的application,默认的为spring.application.name的值
            name: config-consumer
#开放端口用于刷新配置文件 
management: 
    security: 
        #关闭安全访问
        enabled: false
    endpoints:
        web: 
            exposure: 
                #开放所有端口
                include: "*"
    endpoint: 
        helth: 
            show-details: always
                
5)启动程序,调用controller进行测试
  1. get请求访问地址http://localhost:61000/name
  2. 然后改变配置文件,把name属性改掉
name: Saul and Paul
  1. get请求调用刷新配置的端口http://localhost:61000/actuator/refresh
  2. 再次访问地址http://localhost:61000/name

三、高可用配置中心

1、实现原理

  现在的配置中心是单节点的,所有的服务都连接在这个单节点的配置中心上,如果配置中心宕机了,那所有服务的配置就不能更新了,我们将配置中心搭建成集群,在服务和配置中心集群中间,搭建一个负载均衡器,如果一个配置中心的节点宕机了,负载均衡器将请求转到还存活的节点上

2、借助Eureka实现高可用配置中心

(1)服务端代码修改
1)创建一个config-server(配置中心的服务模块)模块,修改配置文件
<dependencies>
    <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>
</dependencies>
2)修改配置文件
@SpringBootApplication
@EnableConfigServer
@EnableDiscoveryClient
public class ConfigServerApplication{
    public static void main(String[] args){
        new SpringApplicationBuilder(ConfigServerApplication.class)
            .web(WebApplicationType.SERVLET)
            .run(args);
    }
}
3)创建配置文件application.yml
server: 
    port: 60000
    
eureka: 
    client: 
        serviceUrl: 
            defaultZone: http://localhost:20000/eureka/

spring: 
    application: 
        name: config-server
    cloud:
        config: 
            server:
                git:
                    #git地址
                    uri: https://github.com/xxxx/config-repo.git
                    #git登录名
                    username: 敲代码的旺财
                    #git密码
                    password: 真帅
                    #配置文件在git下的目录,可以配置多个,主要用于区分开项目
                    #search-paths: test, mall
                    #强制拉取
                    force-pull: true

这里可以启动多个config-server,改下端口号就行了

(2)客户端代码修改
1)创建一个config-client模块,修改配置文件
<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>
    <!-- 配置中心需要他暴露端口,提供动态拉取参数的能力 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-cloud-starter-actuator</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
    </dependency>
</dependencies>
2)修改启动类
@SpringBootApplication
@EnableDiscoveryClient
public class ConfigClientApplication{
    public static void main(String[] args){
        new SpringApplicationBuilder(ConfigClientApplication.class)
            .web(WebApplicationType.SERVLET)
            .run(args);
    }
}
4)创建配置文件application.yml
server: 
    port: 61000
    
#从配置中心获取words属性
myWords: ${words}

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

spring: 
    application: 
        name: config-client
    cloud:
        config: 
            discovery: 
                #启动服务发现功能
                enabled: true
                service-id: config-server-eureka
            #加载的配置文件的环境(这里一般不是写死的 而是通过启动参数,或者系统环境变量来配置)
            profile: prod
            label: master
            #指定配置文件中的application,默认的为spring.application.name的值
            name: config-consumer
#开放端口用于刷新配置文件 
management: 
    security: 
        #关闭安全访问
        enabled: false
    endpoints:
        web: 
            exposure: 
                #开放所有端口
                include: "*"
    endpoint: 
        helth: 
            show-details: always
                

四、配置加密

  数据库密码是一个相当机密的信息,尽量不要让安全级别不高的个人或团队直接接触到。尽管我们程序猿们个个都是信得过的,不会随便登录生产环境做破坏性操作,可也不能保证突发事件的发生。比如今天我和产品经理干了一架,打输了,气不过,拿着密码登录生产环境删库跑路了。
  我们需要引入一个数据安全机制,减少敏感数据的暴露程度,因此需要对三个环节做严格控制。
  数据加密端 就像颁发CA证书一样,必须由一个中心机构用密钥对明文进行加密。这里也一样,需要在生产环境中创建一个特定的服务,专门做加密操作。最重要的是,加密所用的秘钥只能保存在那台机器里,不能对外暴露数据存放端 数据存放端(如GitHub)只能保存加密过后的数据数据解密端 由于密钥都保存在数据加密端,因此数据解密和数据加密必须放在同一个地方进行,加密数据在传给客户端之前要经过解密,不能将秘钥下放到客户端机器上进行解密。

  我们需要引入一个数据安全机制,减少敏感数据的暴露程度,因此需要对三个环节做严格控制

  • 数据加密端:就像颁发CA证书一样,必须由一个中心机构用密钥对明文进行加密。这里也一样,需要在生产环境中创建一个特定的服务,专门做加密操作。最重要的是,加密所用的秘钥只能保存在那台机器里,不能对外暴露
  • 数据存放端:数据存放端(如GitHub)只能保存加密过后的数据
  • 数据解密端:由于密钥都保存在数据加密端,因此数据解密和数据加密必须放在同一个地方进行,加密数据在传给客户端之前要经过解密,不能将秘钥下放到客户端机器上进行解密

1、加密Demo

(1)修改jdk的jce主键
  1. 在Oracle的官网下载jce
    https://www.oracle.com/java/technologies/javase-jce-all-downloads.html
    只有jdk6/7/8并且版本低于6u16/7u171/8u161,才需要下载
  2. 下载的文件解压,得到loacl_policy.jar和US_export_policy.jar,将解压后的文件拷贝到java目录\jre\lib\security下,覆盖同名文件
(2)config-server修改bootstrap.yml配置文件
encrypt:
    #加密用的key,随便写
    key: keyboardDog

发送一个get无参请求到localhost:60001/encrypt/status上,测试配置是否成功

(3)对字符串进行加密/解密
  1. 加密
    发送一个post请求到localhost:60001/encrypt上,使用row传参,参数直接填写想要加密的字符串
  2. 解密
    发送一个post请求到localhost:60001/dencrypt上,使用row传参,参数直接填写加密过后的字符串
(4)修改github上的配置文件
info: 
    profile: prod
    
name: Paul
#这里把字符串换掉,{cipher} 表示这个字符串需要解密 ,后面跟上加密过后的字符串
words: '{cipher}xxxxxxxxxxxxxxxxxxxxx'
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值