Spring Cloud 热度日益提升,注册中心、配置中心的选型是一个必然面对的问题。Eureka 2.0 开源工作宣告停止,Zookeeper 略显笨重,Consul 是某种业务场景下相对较好的选择。Consul 部署简单,兼具注册中心和配置中心,Go 语言带来的高效,可集群部署实现高可用,是 Spring Cloud 的较好搭配。
本场 Chat 将与大家分享 Spring Cloud 选择 Consul 作为注册中心和配置中心的整合过程,与大家分享将 Consul 作为 Spring Cloud 注册中心和配置中心的应用实践及感悟。适合有意向或正在使用 Consul 作为 Spring Cloud 配套的 Java 开发人员。
本场 Chat 你讲学到如下内容:
- 了解 Spring Cloud 采用 Consul 作为注册中心该如何实现。
- 了解 Spring Cloud 采用 Consul 作为配置中心该如何实现。
Spring Cloud 热度日益提升,注册中心、配置中心的选型是一个必然面对的问题。 Eureka 2.0 开源工作宣告停止,Zookeeper 略显笨重,相比之下,Consul 就是很多业务场景下较好的选择。Consul 部署简单,兼具注册中心和配置中心,Go 语言带来了高效,可集群部署能实现高可用,综合来看是 Spring Cloud 的较好搭配。
本场 Chat 中,作者将与大家分享 Spring Cloud 选择 Consul 作为注册中心和配置中心的整合过程,并结合实例分享应用实践及感悟。
适合有意向或正在使用 Consul 作为 Spring Cloud 配套的 Java 开发人员。
通过本场 Chat 你将学了解到如下内容:
- Spring Cloud 采用 Consul 作为注册中心该如何实现
- Spring Cloud 采用 Consul 作为配置中心该如何实现
Consul 作为服务注册中心的思路是各个服务将自身注册到 Consul,调用方从 Consul 获取特定服务的提供方列表,再访问服务提供方进行服务的调用。当 Consul 中某个服务的提供方进行增减时,调用方会通过 Consul 感知到这一变化并进行负载轮询列表更新,实现服务的在线扩容。
Consul 作为配置中心的思路是各个服务启动后先连接 Consul 服务,并从其 KV 存储中按优先级获取相应的配置项,并将配置加载到程序中,可以形象地比喻为将 application.yml 配置服务化。当 Consul 中配置更新时,依赖的服务可以定期检测到这个变化并应用到程序中,实现在线配置更新。
3. Consul 搭建 3.1 dev 模式运行Consul 官网:https://www.consul.io/
官方文档:https://www.consul.io/docs/index.html
在 Consul 官网上 https://www.consul.io/downloads.html 下载相对应的系统版本,本文以 CentOS7 为例,将下载下来的包解压后,运行 consul 文件即可启动 dev 模式的 Consul 服务。
chmod 777 ./consul ./consul
3.2 正常模式单机运行
dev 模式是不进行数据存储的,线上环境需要开启可存储数据的模式,非dev模式的单节点命令示例如下:
nohup ./consul-service/consul agent -server -bootstrap-expect 1 -data-dir ./consul-service/data -config-dir=./consul-service/config -client=0.0.0.0 -ui >./consul-service/consul.out&
简单解释下主要参数:
- server : 定义 agent 运行在 server 模式。
- bootstrap-expect :在一个 datacenter 中期望提供的 server 节点数目,当该值提供的时候,consul 一直等到达到指定 server 数目的时候才会引导整个集群,该标记不能和 bootstrap 共用。
- bind:该地址用来在集群内部的通讯,集群内的所有节点到地址都必须是可达的,默认是 0.0.0.0。
- data-dir:数据存储目录。
- config-dir:配置目录。
- client:Consul 服务侦听地址,这个地址提供 HTTP、DNS、RPC 等服务,默认是 127.0.0.1 所以不对外提供服务,如果你要对外提供服务改成 0.0.0.0。
- ui:启动 Web 管理页面
第一台机器 IP 为 172.17.0.3,3 台机器分别执行,均启动 ui:
consul agent -server -bootstrap-expect 3 -ui -node=node1 -client 0.0.0.0consul agent -server -bootstrap-expect 3 -ui -node=node2 -client 0.0.0.0 -join 172.17.0.3consul agent -server -bootstrap-expect 3 -ui -node=node3 -client 0.0.0.0 -join 172.17.0.3
此时三台机器上的数据会进行同步,如果需要保障客户端访问集群的可靠性,需要在中间加一层 nginx 或其他负载,配置方式此处略。
4. Consul 作为服务注册中心本示例以 IDEA+Maven 的方式进行开发。
4.1 服务端首先是添加 pom.xml 的依赖。
UTF-8 UTF-8 1.8 Finchley.SR1 org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-consul-discovery org.springframework.boot spring-boot-starter-test test org.springframework.cloud spring-cloud-dependencies ${spring-cloud.version} pom import
然后是配置 application.yml。
server: port: 9201spring: application: name: springtest-service message: encoding: UTF-8 cloud: consul: host: 127.0.0.3 port: 8500 discovery: register: true instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port} service-name: ${spring.application.name} port: ${server.port} healthCheckPath: /actuator/health healthCheckInterval: 15s
警告:如果您使用Spring Cloud Consul Config,上述值将需要放置在 bootstrap.yml 而不是 application.yml 中。
consul 段说明
host
:consul 服务的 IP
port
:consul 服务的端口
discovery 段配置说明
register
:是否注册到配置中心
instance-id
:实例唯一 ID
service-name
:服务名
port
:端口
healthCheckPath
:健康检查访问路径,consul 服务器会定时访问次服务的该 url 以检测是否健康
healthCheckInterval
:健康检查时间间隔
最后上代码 application.java。
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.discovery.DiscoveryClient;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;@EnableDiscoveryClient@RestController@SpringBootApplicationpublic class SpringtestServerApplication { @Autowired private DiscoveryClient discoveryClient; public static void main(String[] args) { SpringApplication.run(SpringtestServerApplication.class, args); } /** * 获取所有服务 */ @RequestMapping("/services") public Object services() { return discoveryClient.getServices(); } @RequestMapping("/home") public String home() { return "Hello World"; }}
启动后,Consul 的 Service 列表中就会出现这个服务。
此时访问 http://localhost:9201/home 会输出 Hello World。
4.2 客户端先是配置依赖 pom.xml。
org.springframework.boot spring-boot-starter-web org.springframework.cloud spring-cloud-starter-consul-discovery org.springframework.boot spring-boot-starter-test test
接下来是配置文件 application.yml。
server: port: 9202spring: application: name: springtest-client cloud: consul: host: 192.168.140.128 port: 8500 discovery: register: false
最后上代码 application.java。
@EnableDiscoveryClient@RestController@SpringBootApplicationpublic class SpringtestClientApplication { public static void main(String[] args) { SpringApplication.run(SpringtestClientApplication.class, args); } @Autowired private LoadBalancerClient loadBalancer; @Autowired private DiscoveryClient discoveryClient; @Autowired RestTemplate restTemplate; @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } /** * 从所有服务中选择一个服务(轮询) */ @RequestMapping("/discover") public Object discover() { return loadBalancer.choose("springtest-service").getUri().toString(); } /** * 获取所有服务 */ @RequestMapping("/services") public Object services() { return discoveryClient.getInstances("springtest-service"); } @RequestMapping("test") public String test(){ String result= restTemplate.getForEntity("http://springtest-service/home",String.class).getBody(); return result; }}
一般常用 restTemplate.getForEntity("http://springtest-service/home",String.class)
这种方式调用,方便快捷。
此时访问 http://localhost:9202/test 会输出 Hello World。
5. Consul 作为配置中心 5.1 配置Consul 添加 kv 的方式:http://ip:8500/ 进入 Web 管理页面,点击 key/value 进入 kv 管理页面,点击右上角 create 创建 kv。
consul 页面上添加 key 为:
config/springtest-service/data
value 为:
test: testValue: consul--asdf34testConfig: test-value: consul123--asdf34
生产环境中访问 Web 管理页面比较困难,此时需要通过命令去维护,一种方式是直接用 Consul 的命令去操作,但是需要运行在有 Consul 程序的机器上,还有另外一种通用的方式就是通过 webapi 访问:
获取
curl http://ip:8500/v1/kv/config/application/data
key 为 config/application/data
返回值:
[ { "LockIndex": 0, "Key": "config/application/data", "Flags": 0, "Value": "dGVzdDoKICB0ZXN0VmFsdWU6ICBhcHBiYXNlLS1hc2RmMzQKdGVzdENvbmZpZzoKICB0ZXN0LXZhbHVlOiBhcHBiYXNlLS1hc2RmMzQ=", "CreateIndex": 1983705, "ModifyIndex": 1983711 }]
其中 value 是 base64 加密的,需要进行解密。
echo "dGVzdDoKICB0ZXN0VmFsdWU6ICBhcHBiYXNlLS1hc2RmMzQKdGVzdENvbmZpZzoKICB0ZXN0LXZhbHVlOiBhcHBiYXNlLS1hc2RmMzQ=" | base64 -d
得到如下明文结果:
test: testValue: appbase--asdf34testConfig: test-value: appbase--asdf34
完整的一次性获取命令:
curl http://ip:8500/v1/kv/config/application/data |grep "Value" | sed 's/ "Value": "//' | sed 's/",//' |base64 -d
赋值
curl \ -X PUT \ -d "aaa1231 1234324qasd" \ http://ip:8500/v1/kv/my-key
删除
curl -X DELETE http://ip:8500/v1/kv/my-key
5.2 开发实现
本示例以 IDEA+Maven 的方式进行开发。
首先是添加 pom.xml 的依赖。
org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-actuator org.springframework.boot spring-boot-configuration-processor org.springframework.cloud spring-cloud-starter-consul-discovery org.springframework.cloud spring-cloud-starter-consul-config org.springframework.boot spring-boot-starter-test test org.projectlombok lombok 1.18.6
然后是配置文件 bootstrap.yml。
server: port: 9201spring: application: name: springtest-service profiles: active: dev cloud: consul: host: 127.0.0.1 port: 8500 discovery: register: true instance-id: ${spring.application.name}:${spring.cloud.client.ip-address}:${server.port} service-name: ${spring.application.name} port: 9201 healthCheckPath: /actuator/health healthCheckInterval: 15s config: enabled: true format: YAML prefix: config defaultContext: application profileSeparator: ',' data-key: data
注:discovery 段是添加到 consul 注册中心的。
config 段说明:enabled:true
允许配置中心
format:YAML
表示 consul 中的 key-value 中的 value 内容,采用 YAML 格式,据说有四种 YAML PROPERTIES KEY-VALUE FILES
prefix: config
表示 consul 用于存储配置的文件夹根目录名为 config
defaultContext: application
表示配置文件对应的默认应用名称(优先获取当前服务名称配置,没有的到 application 里找)
profileSeparator: ','
表示如果有多个 profile(eg:开发环境 dev,测试环境 test……),则 key 名中的 profile 与 defaultContext 之间,用什么分隔符来表示(例如 config/springtest-service,dev/data)
data-key: data
表示最后一层节点的 key 值名称,一般默认为 data
接下来是一个配置读取类 TestConfig.java。
import lombok.Data;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.Configuration;@ConfigurationProperties(prefix = "test-config")@Configuration@Datapublic class TestConfig { private String testValue;}
最后是一个测试程序 App.java。
App.java
@EnableDiscoveryClient@RestController@SpringBootApplicationpublic class SpringtestServerApplication { @Autowired private DiscoveryClient discoveryClient; @Value("${test.testValue}") private String testValue; @Autowired private TestConfig testConfig; public static void main(String[] args) { SpringApplication.run(SpringtestServerApplication.class, args); } @RequestMapping("/test") public String test(String id) { return "test"+id+"/"+testValue+"/"+testConfig.getTestValue(); }}
这里面采用了两种获取配置的方式:@Value 和 @ConfigurationProperties,都能进行配置获取,但是后者可以实现配置更新后动态更新。
5.3 配置优先级优先级上面的最高。
config/testApp,dev/config/testApp/config/application,dev/config/application/
6. 总结
综上,讲述了 Consul 如何部署, Spring Cloud 采用 Consul 作为注册中心和配置中心该如何实现,希望能够给大家带来帮助。
本文首发于 GitChat,未经授权不得转载,转载需与 GitChat 联系。
阅读全文: http://gitbook.cn/gitchat/activity/5c9db44771bc5c38e5b1ba31
您还可以下载 CSDN 旗下精品原创内容社区 GitChat App ,阅读更多 GitChat 专享技术内容哦。