利用Spring Cloud Config结合Bus实现分布式配置中心的步骤
概述
假设现在有个需求:
我们的应用部署在10台机器上,当我们调整完某个配置参数时,无需重启机器,10台机器自动能获取到最新的配置。
如何来实现呢?有很多种,比如:
1、将配置放置到一个数据库里面,应用每次读取配置都是直接从DB读取。这样的话,我们只需要做一个DB变更,把最新的配置信息更新到数据库即可。这样无论多少台应用,由于都从同一个DB获取配置信息,自然都能拿到最新的配置。
2、每台机器提供一个更新配置信息的updateConfig接口,当需要修改配置时,挨个调用服务器的updateConfig接口。
3、借助redis来实现,把配置信息放置到redis上,但是这样子,就每次都得去redis读取,多了一些网络请求。
上面这三种方法是最容易想到的,也很容易做,但是缺点当然也非常的多。虽说缺点很多,但是某些传统企业还真是这么干的。
在互联网企业里,基本没见过这么玩的,都是会使用分布式配置中心。用开源的或者自己实现,目前开源的分布式配置中心有很多,而spring cloud config就是其中的佼佼者。下面我们就用spring cloud config来实现一个分布式配置中心。
是否使用最新的Spring Boot 2.0 版本
我曾经使用最新的spring cloud 2.0做了一个分布式是配置中心的demo。原本以为很简单,但是居然足足花了一天才搞定。有以下几个原因:
1、spring cloud对应的文档没有完全更新,出了问题,在文档里找不着;
2、目前使用2.0版本的公司很少,网上也没什么具体实战文章介绍。出了问题后,百度是找不到解决方案的。而google也基本很难找到方案,都是一些零星的知识碎片;
3、2.0这个版本,config和bus这块有些小变动,如果还按照1.5.x的版本来弄的话,是行不通的。
基于上面几个原因,建议使用1.5.x的版本靠谱些。下面这篇文章会以下面的版本来介绍的:
spring boot:
1.5.2.RELEASE
对应的spring cloud使用:
Dalston.RELEASE
搭建spring cloud config server
如果你只是想把配置统一由spring cloud config来管理,而暂时不想做配置中心的高可用的话,则只需要config和bus两个组件就够了。但是如果要保证高可用,还得使用spring cloud的注册发现组件。
除了config和bus之外,我们还需要使用git。因为spring cloud config是使用git来做版本管理的。
基于spring cloud config做一个配置中心,很简单,只要几个小步骤就搞定了。
【1】引入config和bus组件
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
【2】启动类使用@EnableConfigServer注解
package spring.cloud.config; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.config.server.EnableConfigServer; @EnableConfigServer @SpringBootApplication public class ConfigApplication { public static void main(String[] args) { SpringApplication.run(ConfigApplication.class, args); } }
【3】application.yml文件配置rabbitmq和git仓库
server: port: 8040 spring: application: name: spring-cloud-config-server cloud: config: server: git: uri: https://gitlab.xxxxxx.com/config/xxxxxxx.git search-paths: username: xxxxx password: xxxxxx activemq: host: 127.0.0.1 port: 5672 username: guest password: guest management: security: enabled: false
配置RabbitMQ是因为bus组件需要使用它来通知客户端,配置有变动。另外,记得使用
management: security: enabled: false
将验证关闭掉,不然后面的操作,老是报授权错误。
到此服务端配置中心已经搞定了。现在你就可以在服务端先做个小实验,提交一个demo-dev.properties文件,文件的内容如下:
address=hello
然后使用
http://localhost:8040/demo/dev
如果能输出
{“address”:”hello”}
就说明spring cloud config跟git的交互是ok的。
客户端接入配置中心
我们的目标:
当把配置信息修改完提交到git上后,所有接入到spring cloud config的客户端马上能收到通知,并且拿到最新的配置信息。
下面介绍如何实现这个目标。
客户端只需要做几个小步骤即可完成接入动作。
【1】引入依赖
<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.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
引入spring-boot-starter-web只是为了做实验而已。
【2】配置RabbitMQ和引入配置中心的url
application.properties
spring.application.name=spring-cloud-config-client1 server.port=8042 management.security.enabled=false spring.rabbitmq.host=127.0.0.1 spring.rabbitmq.port=5672 spring.rabbitmq.username=guest spring.rabbitmq.password=guest
bootstrap.properties
spring.cloud.config.name=demo spring.cloud.config.profile=dev spring.cloud.config.label=master spring.cloud.config.uri=http://localhost:8040/
有三个注意点:
1、关闭验证:management.security.enabled=false
2、spring cloud config相关的配置一定一定要放到bootstrap.properties里
3、使用spring.cloud.config.uri指定配置中心的地址
另外,对于客户端来说,启动类是不用加上任何跟config和bus有关的注解的。
到此客户端搞定了,我们可以使用一个controller来开始做实验了。
package springcloudconfig.client; import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.context.config.annotation.RefreshScope; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RefreshScope public class HelloController { @Value("${address}") private String address; @RequestMapping("/address") public String getAddress() { return this.address; } }
假设上面的HelloController需要用到address这个配置,只需要使用@RefreshScope和@value注解就可以了
@RefreshScope public class HelloController {}
@Value("${address}") private String address;
为了验证客户端是否能拿到最新的配置信息,提供一个
@RequestMapping("/address") public String getAddress() { return this.address; }
方法。
我们修改一下demo-dev.properties文件,将值改成
address=hello update
并提交到git上。这个时候我们调用getAddress接口
http://localhost:8041/address
发现并没有拿到最新的值。那是因为push到git的这个动作做完后,我们没有通知到spring cloud bus。可以使用postman来做一个post请求,调用如下接口,来通知bus。
http://localhost:8040/bus/refresh
这个接口一旦调用成功,bus会利用RabbitMQ通知所有的客户端,配置已经更新。
特别注意:
我们是调用服务端的/bus/refresh接口,不是去调用客户端的/bus/refresh接口。
如果每次提交,都要去调用服务端的/bus/refresh接口,那这个也太麻烦了。可以使用webhook来帮一下忙。
如果你们用的是新的gitlab,那么只需要在工程里面,点击【Settings】,再点击【Integrations】,就可以设置webhook了,如下图:
url里面填入配置中心服务端的/bus/refresh接口地址,然后点击【添加Webhook】就可以了。
与携程的阿波罗对比
Spring Cloud Config的精妙之处在于它的配置存储于Git,这就天然的把配置的修改、权限、版本等问题隔离在外。通过这个设计使得Spring Cloud Config整体很简单,不过也带来了一些不便之处。
下面尝试做一个简单的小结:
功能点 | Apollo | Spring Cloud Config | 备注 |
---|---|---|---|
配置界面 | 一个界面管理不同环境、不同集群配置 | 无,需要通过git操作 | |
配置生效时间 | 实时 | 重启生效,或手动refresh生效 | Spring Cloud Config需要通过Git webhook,加上额外的消息队列才能支持实时生效 |
版本管理 | 界面上直接提供发布历史和回滚按钮 | 无,需要通过git操作 | |
灰度发布 | 支持 | 不支持 | |
授权、审核、审计 | 界面上直接支持,而且支持修改、发布权限分离 | 需要通过git仓库设置,且不支持修改、发布权限分离 | |
实例配置监控 | 可以方便的看到当前哪些客户端在使用哪些配置 | 不支持 | |
配置获取性能 | 快,通过数据库访问,还有缓存支持 | 较慢,需要从git clone repository,然后从文件系统读取 | |
客户端支持 | 原生支持所有Java和.Net应用,提供API支持其它语言应用,同时也支持Spring annotation获取配置 | 支持Spring应用,提供annotation获取配置 | Apollo的适用范围更广一些 |
我个人还是推荐使用Spring Cloud Config,很轻量级、且社区活跃,遇到问题很好找到解决方案。另外呢,我个人认为阿波罗和Spring Cloud Config的区别就只是有木有界面而已。界面做得到的,我们通过git也可以的,只是用户体验没那么好而已。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对我们的支持。