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请求的服务端都要注销再注册了。

原文地址:https://www.cnblogs.com/koushr/p/11899439.html