zoukankan      html  css  js  c++  java
  • springcloud第四篇:Spring Cloud Config

    配置中心,老生长谈的问题。之前在平安的时候,就调研过各种开源实现,发现了携程的apollo很不错。spring cloud生态也提供了spring cloud config。下面会先讲解spring cloud config,再讲解apollo,然后再对比两个,看各自优缺点。

    spring cloud config

    spring cloud config分为服务端 config server和客户端 config client。config server要多节点部署以保证要高可用,config client就是我们具体的应用。spring cloud config依赖于github或者gitlab或者svn,会把配置文件放在相应仓库地址的相应目录中,然后config server会去对应目录中读取文件。

    config server搭建

    1、引入依赖:

    <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>

    2、在配置文件中添加

    server.port=8001
    spring.application.name=spring-cloud-config-server
    eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8000/eureka/
    spring.cloud.config.server.git.uri=https://github.com/koushr/spring-cloud-examples.git
    spring.cloud.config.server.git.search-paths=config-repo
    spring.cloud.config.server.git.username=koushr
    spring.cloud.config.server.git.password=xxx

    git.uri指定github/gitlab/svn的仓库地址,git.search-paths指定仓库中存放配置文件的目录,可以是多个,因为不同客户端应用的配置文件一般会放在不同的目录中。假如不同应用的配置文件放在同一目录的话,就显得太乱,不太好管理。如果分开放,又会有一个很致命的问题,那就是每新建一个项目,config server都要修改代码,然后重启。这点不能接受。还需要指定访问仓库时的用户名和密码。

    本例子假定有一个占用8000端口的eureka server,把config server也注册到注册中心。

    3、在启动类上添加@EnableEurekaClient、@EnableConfigServer注解。

    启动应用,config server就算搭建好了。

    config client

    1、引入依赖

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

    2、在配置文件中添加

    注意,config client要额外用bootstrap.properties配置文件。

    spring.cloud.config.name=neo-config
    spring.cloud.config.profile=dev
    spring.cloud.config.label=master
    spring.cloud.config.discovery.enabled=true
    spring.cloud.config.discovery.serviceId=spring-cloud-config-server
    eureka.client.serviceUrl.defaultZone=http://127.0.0.1:8000/eureka/

    config.name指定要读取的配置文件的名称,可以设置多个,用逗号分开。config.profile指定要读取的环境,如dev、test、prd。如果config.name=neo-config,config.profile=dev,则会读取neo-config-dev.properties文件中的配置项。如果config.name=neo-config,neo-config2,config.profile=dev,则会读取neo-config-dev.properties、neo-config2-dev.properties文件中的配置项。

    config.label指定仓库的分支。config.discovery.enabled=true表示启用注册中心发现,config.discovery.serviceId指定要发现的配置中心名称,当然前提条件是必须把自己也注册到注册中心。

    3、在启动类上添加@EnableDiscoveryClient注解。

    那么怎么用呢?直接用@Value("${key}")即可读取配置项的值

    @RestController
    public class HelloController {
        @Value("${neo.hello}")
        private String hello;
    
        @RequestMapping("/helloConfig")
        public String hello() {
            return this.hello;
        }
    }

    调用/helloConfig接口就返回neo.hello的值。

    现在应用已经可以读取配置中心的配置项了,但是读取不了更新后的值。什么意思呢?编辑neo-config.properties文件,修改neo.hello的值。再次调用/helloConfig接口,拿到的是旧值,新值获取不了。

    解决办法:

    1、在使用配置项的类上添加@RefreshScope注解。

    2、修改完配置项的值后调用客户端的/actuator/refresh接口。这就要求客户端应用放开/actuator/refresh接口,引入actuator依赖即可

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

    调用客户端应用的/actuator/refresh接口后,客户端应用会重新从config server拉取最新配置项。

    到这一步,有两个问题。

    第一个问题:客户端应用节点有很多,要想让所有节点都能获取到最新的配置项值,得调用所有节点的接口。这可不太容易。通过ip调用的话,太麻烦,漏一个就麻烦了,又如果这些ip是内网ip的话,可能根本还调不通,甚至有时候我们根本还拿不到这些ip。假如通过域名调用的话,由于负载均衡策略的存在,根本不能调用到所有的节点。

    第二个问题:发现客户端在处理/actuator/refresh请求时会把自己从注册中心注销掉,然后又注册上去。

    利用消息总线可以解决第一个问题。

    原理是我们不再调用客户端的接口,而是调用conifg server的接口,服务端会向消息队列中写入消息,每个客户端启动后都会新建一个不同的消费组,收到消息后会从服务端重新拉取配置项值。

    整改步骤:

    1、在config server和config client都引入spring cloud bus依赖,由于要调用服务端的actuator接口,所以服务端还得引入actuator依赖。消息总线要依赖消息队列,目前只有两种实现,kafka和rabbitmq,我们还是用熟悉的kafka

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

    2、在配置文件中添加spring cloud bus相关的配置。config server在application.properties文件中添加,config client在bootstrap.properties文件中添加

    spring.cloud.bus.enabled=true
    spring.cloud.stream.kafka.binder.brokers=192.168.56.100:9092
    management.endpoints.web.exposure.include=*

    第一行表示启用spring cloud bus,第二行指定kafka集群地址,kafka集群版本最好跟上面依赖引入的kafka客户端版本一致,否则可能会出现一些奇怪的问题。

    按照以上方案整改后,修改完配置项,调用服务端的/actuator/bus-refresh接口,客户端就会重新从服务端拉取配置项的值,这就解决了第一个问题。

    第二个问题仍然存在,而且更严重了,现在不光是客户端要注销再注册,就连收到/actuator/bus-refresh请求的服务端都要注销再注册了。

  • 相关阅读:
    iOS ARC下命名规则
    performSelector may cause a leak because its selector is unknown
    performSelector may cause a leak because its selector is unknown
    Block的Retain Cycle的解决方法
    Block的Retain Cycle的解决方法
    iOS 5 ARC 入门
    iOS 5 ARC 入门
    Xcode 5 SVN配置
    Python基本语法_基本数据类型_序列类型详解
    Python基本语法_基本数据类型_序列类型详解
  • 原文地址:https://www.cnblogs.com/koushr/p/11899439.html
Copyright © 2011-2022 走看看