一、背景
由于Eureka官方已经正式宣布,自2.0起不再维护该项目,如果需要使用2.x,自行承担风险。
项目之前使用的Eureka,现在不维护了则需要寻找替代方案。现在Spring Cloud官方推荐Spring Cloud Consul替换Eureka作为注册中心,那么什么是Consul呢?
官网的描述:
HashiCorp Consul 是一种服务网络解决方案,可以帮助团队在本地和多云环境以及运行时之间管理服务之间的安全网络连接。Consul 提供服务发现、服务网格、流量管理和对网络基础设备的自动更新。您可以单独使用这些功能,也可以在单个 Consul 部署中将它们一起使用。
能干什么?
服务注册与发现:consul提供服务注册与发现功能,服务启动时会向consul注册自己的信息,其它服务可以通过consul来查询特定服务的信息,从而实现不同服务之间的通信。
健康检查:consul提供了多种健康检查的方式,对服务进行健康检查,确保服务能正常提供服务。如果检测到服务不再健康,consul会自动将其标记为不可用,并将流量路由到其它健康的实例。
KV存储:它提供了一个分布式的K/V存储系统,可用于配置和存储数据。也就是它能当配置中心的原因。
一致性的保证:consul使用Raft协议来确保数据的一致性,保证节点之间数据的一致。
DNS接口:提供了DNS接口,允许使用域名进行服务发现,使得服务发现变得更简单通用。
多数据中心:consul支持多个数据中心集群,支持在不同的地区部署多个consul集群,并在他们之间进行通讯和同步。
可视化界面:提供了一套可视化的页面,非常方便查看集群信息和进行相应的配置。
二、配置中心
1. 什么是配置中心?
在现在分布式系统和微服务架构中,每个服务都有自己的配置,这些配置又分为公共的配置(每个服务都相同的部分)和私有的配置(这个服务特有的部分配置)。并且在不同的环境中配置又不尽相同,例如在开发环境和生成环境的数据库配置就会不一样,如果单独对每个服务进行配置和管理会显得及其麻烦,所以集中式管理的思想就诞生了!
配置中心是一个集中管理和分发应用程序配置的系统。在现代分布式系统和微服务架构中,配置中心起着至关重要的作用,因为它能够提供一种统一的方式来管理不同服务的配置,并且支持动态更新配置而无需重启服务。
2. Spring Cloud Config配置中心
项目之前使用spring cloud config作为配置中心,但是需要配合git存储,且还需要配合Spring Cloud Bus来实现动态刷新配置,动态刷新配置这一块不是很方便。
3. Consul作为配置中心
了解到了上面提到的,K/V存储可以存储配置信息。Spring Cloud官方还声明Consul可以作为Spring Cloud Config配置中心的替代方案。并且不需要git配合,不需要集成Spring Cloud Bus即可实现动态刷新配置,它通过长轮询的方式从consul上检测到配置的变化,然后通知到客户端。所以,我们决定使consul作为配置中心。
三、实战演示
1. Consul下载
下载地址:Install | Consul | HashiCorp Developer
2. 在本地启动
启动命令如下,因为我们要做配置中心,配置要持久化,所以采用下面的方式启动,而不是consul.exe agent -dev
consul.exe agent -server -config-dir=C:/ProgramFiles/consul/config -data-dir=C:/ProgramFiles/consul/data -bind=127.0.0.1 -bootstrap-expect=1 -ui
启动成功后,访问http://localhost:8500/,如果出现下面的页面则启动成功。
3. 在pom文件中加入 SpringCloud Consul及其配置中心相关的包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
4. application.yml添加consul的配置
spring:
application:
name: consulMicroservice
profiles:
active: dev
cloud:
consul:
host: localhost
port: 8500
discovery:
healthCheckPath: /management/health
instanceId: consulmicroservice:${spring.application.instance-id:${random.value}}
service-name: consulmicroservice
prefer-ip-address: true
#consul健康检查需要开启actuator的health断点
management:
endpoints:
web:
base-path: /management
exposure:
include:
- health
5. bootstrap.yml添加consul配置中心的相关配置
spring:
application:
name: consulMicroservice
profiles:
active: dev
cloud:
consul:
config:
fail-fast: false # if not in "prod" profile, do not force to use Spring Cloud Config
format: yaml
profile-separator: '-'
# 是否启用配置中心,默认值 true 开启
enabled: true
# 设置配置的基本文件夹,默认值config 可以理解为配置文件所在的最外层文件夹
prefix: config
# 设置应用的文件夹名称,默认值application 一般建议设置为微服务应用名称
default-context: application
# Consul Key/Values 中的Key, 默认为data, Value 对应整个配置文件
data-key: data
#name: consulMicroservice
# 以上配置可以理解为:加载 config/application/下Key 为data 文件夹下公共配置 和 config/jhipsterSampleMicroservice/下Key 为data 的Value 对应的私有配置
watch:
# 等待(或阻塞)监视查询的秒数,默认:55秒,需要小于60,如果需要修改后立刻能读取配置,则需要修改为1秒
wait-time: 55
# 是否开启自动刷新,默认值true 开启
enabled: true
# 刷新频率,单位:毫秒,默认值1000
delay: 1000
discovery:
tags:
- profile=${spring.profiles.active}
- version=#project.version#
- git-version=${git.commit.id.describe:}
- git-commit=${git.commit.id.abbrev:}
- git-branch=${git.branch:}
- context-path=${server.servlet.context-path:}
host: localhost
port: 8500
6. 读取本地配置-启动项目
启动成功后在本地,看到是在8080端口运行。服务也已经注册到consul上了。
7. 在consul上创建相关的配置项
官网上的文件加载顺序:
大概的意思是,项目启动后加载配置文件的顺序如下:
- config/testApp,dev/
- config/testApp/
- config/application,dev/
- config/application/
其中,config/testApp文件夹中的配置,只适用于testApp,config/application文件夹中的配置对所有注册到consul上的服务都可用。
接下来,我按照这个结构在consul上创建文件夹config/application存放公共的配置和文件夹config/consulMicroservice用来存放consulMicroservice私有的配置。
在application文件夹中添加公共配置,比如jwt token的密钥
在consulMicroservice文件夹中添加私有的配置,并把端口修改为8090
8. 读取配置中心的配置-启动项目
在启动项目之前,我们先加一个controller来读取config/spplication中的配置,看能否读取到。注意需要加上@RefreshScope这个注解。
@RestController
@RefreshScope
public class DynamicConfigResource {
private final Logger log = LoggerFactory.getLogger(DynamicConfigResource.class);
@Value("${spring.security.authentication.jwt.base64-secret:null}")
private String jwtKey;
@GetMapping("/jwt")
public String getConfigValues() {
log.info("JWT Key: {}", jwtKey);
return "jwt Config: " + jwtKey;
}
}
项目启动之后,我们可以看在在8090端口上运行,说明成功加载了配置中心config/consulMicroservice中的配置数据。
接下来我们继续测试,能否读取到config/spplication中的公共配置。浏览器中访问:http://localhost:8090/jwt
将配置中心中公共配置打印出来了,说明也成功的读取到了config/application中的数据。
9. 配置动态刷新
这对我们项目来说很重要的一个特性。当配置中心的配置发生变化时,客户端能够获取到最新的配置。它是通过长轮询,和下面的两个机制实现的。
- Consul Watch机制:监视配置变化,当配置发生变化时,通知客户端。
- @RefreshScope注解:标记需要动态刷新的Bean,当接收到刷新事件时,这些Bean会重新加载最新的配置。
首先,我们先在配置中心更新 base64-secret的值。直接在后面加"test_refresh",然后保存。
然后,我们可以看到log中输出了下面的信息,证明配置更新了。可能不会立即看到,因为默认每次轮询等待时间为55s,如果希望立刻看到变化需要修改配置:spring.cloud.consul.config.watch.wait-time = 1
接下来,我们再到浏览器中请求一下:http://localhost:8090/jwt 可以看配置已经动态刷新。
最后,我们来总结一下动态刷新配置的原理。
Consul使用一种叫做长轮询的机制来检测配置的变化。客户端发送一个HTTP请求到Consul服务器,服务器在有新的变更发生时立即返回响应。如果在指定的wait-time内没有变化,服务器会在超时前返回一个空响应。这种机制可以减少服务器的负载,因为客户端不会频繁地发起请求,而是等待配置变更事件的发生。