赞
踩
如果微服务架构中没有使用统一配置中心时,所存在的问题:
在SpringCloud中我们使用config组件来作为统一配置中心:
废话不多说,本小节我们来开发统一配置中心的server端,在IDEA中新建一个Spring Initializr项目,并选择相应的模块:
项目的pom.xml文件配置的依赖如下:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-monitor</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
因为config server是需要到git上拉取配置文件的,所以还需要在远程的git上新建一个存放配置文件的仓库,我这里使用的是码云:
创建好后,新建一个文件,然后把订单服务的配置文件内容粘贴进来:
注:我这里事先已经存在一个商品服务和订单服务
回到config项目中,编辑application.yml配置文件内容如下:
spring:
application:
name: config
cloud:
config:
server:
git:
uri: https://gitee.com/Zero-One/config-repo # 远程git仓库的地址
username: username # 以及相应的账户名
password: password # 和密码
basedir: E:Java_IDEAconfigasedir # 可以使用这个配置项来指定本地git仓库的路径
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
server:
port: 8974
在启动类上,加上@EnableConfigServer
注解,声明这是一个config-server。代码如下:
package org.zero.springcloud.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
@EnableConfigServer
public class ConfigApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigApplication.class, args);
}
}
启动项目,访问如下地址,可以看到能够访问到配置文件的内容:
如果访问.properties格式的,还会自动进行转换:
.json格式的也能够进行转换:
注:如果配置文件的内容格式有问题的话,访问会报500错误。我们可以利用这个特性,来检查我们的配置文件是否正确
在上图访问的地址中可以发现,访问的配置文件名后面还有一个-a,这其实是config的访问规则。后面必须要跟个-xxx,所以在创建文件的时候,最好是按这种命名规则来创建。配置文件的访问规则如下:
/{name}-{profiles}.yml
/{label}/{name}-{profiles}.yml
name : 文件名,一般以服务名来命名
profiles : 一般作为环境标识
lable : 分支(branch),指定访问某分支下的配置文件
有一点值得注意的是,如果有两个前缀名相同文件,例如一个order.yml,一个order-dev.yml。那么在访问相同前缀的文件时,config-server会对这两个文件进行一个合并。例如order.yml有一段配置是order-dev.yml没有的,理应访问order-dev.yml的时候是没有那段配置的,但访问的结果却是它俩合并之后的内容,即order-dev.yml会拥有order.yml里所配置的内容。
在上一小节中,我们介绍了config-server的使用以及配置文件的访问规则,本小节将介绍config-client端的使用,我们以订单服务为例。
在订单服务工程的pom.xml文件中,增加如下依赖配置:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
注:商品服务工程中也增加这个依赖,这样两个服务都可以从config-server中读取配置了
然后将application.yml重命名为bootstrap.yml,并修改内容如下:
spring:
application:
name: order
cloud:
config:
discovery:
enabled: true
service-id: CONFIG # 注册中心的服务名
profile: dev # 指定配置文件的环境
注:之所以要用bootstrap.yml,是因为启动SpringBoot项目时,会优先读取bootstrap.yml里的配置,然后才会读取application.yml。如果不通过bootstrap.yml里的配置,先从配置中心拉下相应的配置文件,就会报错
重启项目,使用创建订单接口,测试一下是否正常:
统一配置中心和服务注册中心一样,都是需要高可用的,不然配置文件都没有的话,项目自然没法跑起来了。所以我们来看看如何使config-server能够高可用。
config-server也属于是一个微服务,所以让其高可用很简单,只需要启动多个服务实例即可。首先我们来复制几个config-server的实例,跑在不同的端口上:
启动后,到eureka上可以看到也都注册成功了,这样我们就有了三个config-server实例:
其他服务通过负载均衡策略,就能够调用这几个config-server实例,轻松实现高可用
还有一个需要注意的点是服务注册中心地址端口的问题,我们都知道eureka-server的默认端口是8761,如果我们现在将eureka-server的端口改成8762,那么订单服务就会启动不了。因为在bootstrap.yml配置文件中,并没有配置eureka-server的地址。
项目启动的时候会优先读取bootstrap.yml,按照配置的内容去配置中心拉取配置文件,但是在此之前订单服务需要先去注册中心上找配置中心的调用地址,如果eureka-server端口更改了的话,就会访问不到配置中心,自然也就无法调用配置中心拉取配置文件了,现在我们之所以可以访问是因为SpringBoot默认访问的是本地的8761端口。
所以我们需要修改远程git仓库上的配置文件内容如下:
然后在bootstrap.yml中增加eureka-server的配置才对:
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
这也是一个小细节,如果没有注意的话,容易掉进这个坑。
在上两个小节中,我们学习了统一配置中心的server端以及client端的使用,也成功拉取了相应的配置文件。但是这样仍然不够,因为还不能做到自动刷新配置文件,例如我在git上更改了配置文件,还需要重启服务才能够读取到最新的配置。所以本小节将介绍一下如何使用Spring Cloud Bus实现自动刷新配置,Bus在这里是总线的意思。
示意图:
Spring Cloud Bus会向外提供一个http接口,即图中的/actuator/bus-refresh。我们将这个接口配置到远程的git上,当git上的文件内容发生变动时,就会自动调用/bus-refresh接口。Bus就会通知config-server,config-server会发布更新消息到消息队列中,其他服务订阅到该消息就会信息刷新,从而实现整个微服务进行自动刷新。
由于实现配置自动刷新,需要用到消息中间件,所以还得安装,我这里使用RabbitMQ。并且是在CentOS上使用docker进行安装,docker的版本如下:
[root@01server ~]# docker info |grep "Server Version"
Server Version: 18.03.1-ce
[root@01server ~]#
安装并启动rabbitmq:
[root@01server ~]# docker run -d --hostname my-rabbit -p 5672:5672 -p 15672:15672 rabbitmq:3.7.3-management
...
[root@01server ~]#
进入容器里,添加超级管理员用户:
[root@01server ~]# docker exec -it 1ca60f11d6d9 bash # 进入容器
root@my-rabbit:/# rabbitmqctl add_user admin password # 添加用户,用户名为admin,密码为password
Adding user "admin" ...
root@my-rabbit:/# rabbitmqctl set_user_tags admin administrator # 设置用户权限为超级管理员
Setting tags for user "admin" to [administrator] ...
root@my-rabbit:/# rabbitmqctl set_permissions -p /${user_name} admin '.*' '.*' '.*' # 设置远程登录权限
root@my-rabbit:/#
如果你的系统防火墙没有关闭的话,还需要开放相应的端口:
[root@01server ~]# firewall-cmd --zone=public --add-port=15672/tcp --permanent
success
[root@01server ~]# firewall-cmd --zone=public --add-port=5672/tcp --permanent
success
[root@01server ~]# firewall-cmd --reload
success
[root@01server ~]#
使用浏览器访问${ip}:15672
,进入登录界面:
登录之后才能进入到管理页面:
安装好RabbitMQ后,我们就可以着手实现配置的刷新了。首先我们需要在config项目中,增加Spring Cloud Bus依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
注:商品服务以及订单服务也需要加入这个依赖
然后在配置文件中,配置rabbitmq的地址以及用户密码,修改config服务的配置如下:
spring:
application:
name: config
cloud:
config:
server:
git:
uri: https://gitee.com/Zero-One/config-repo
username: username
password: password
basedir: E:Java_IDEAconfigasedir
# 配置rabbitmq的地址以及用户密码
rabbitmq:
host: 192.168.190.129
port: 5672
username: admin
password: admin
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
# 允许/actuator/bus-refresh接口被外部调用
management:
endpoints:
web:
exposure:
include: "*"
修改商品服务的配置如下:
spring:
application:
name: product
cloud:
config:
discovery:
enabled: true
service-id: CONFIG
profile: dev
rabbitmq:
host: 192.168.190.129
port: 5672
username: admin
password: admin
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
修改订单服务的配置如下:
spring:
application:
name: order
cloud:
config:
discovery:
enabled: true
service-id: CONFIG
profile: dev
rabbitmq:
host: 192.168.190.129
port: 5672
username: admin
password: admin
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
配置好后,将以上项目都重启,然后到RabbitMQ上,可以看到注册上来的队列:
确认都能够正常注册到rabbitmq后,我们到码云上,规范配置文件的名称。修改之前的order.yml为order-dev.yml,并且增加商品服务的配置文件,如下:
并在order-dev.yml文件里,增加一段env配置:
完成配置文件的修改后,再到订单服务项目里,增加一个 EnvController 类,加上@RefreshScope注解实现自动刷新配置,用来测试配置刷新是否正常。代码如下:
package org.zero.springcloud.order.server.controller;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @program: sell_order
* @description:
* @author: 01
* @create: 2018-08-20 23:17
**/
@RestController
@RequestMapping("/env")
@RefreshScope // 这个注解声明了刷新配置的范围,如果使用config配置类的话,就声明到配置类上即可
public class EnvController {
@Value("${env}")
private String env;
@GetMapping("/print")
public String print(){
return env;
}
}
重启订单服务项目,访问/env/print
接口,返回的结果如下:
这时,我们再到码云上修改order-dev.yml文件里的env配置为beat,如下:
然后访问bus用于刷新配置的接口:
稍等一会,控制台应该会打印刷新日志,接着再访问之前的测试接口,返回beta则说明刷新是有效的。因为这个过程中,我们并没有重启订单服务或配置中心服务:
到了本小节,就代表我们已经成功集成了RabbitMQ以及Spring Cloud Bus进行配置文件的动态刷新,但是我们目前依旧需要手动去访问Bus用于刷新配置的接口,才能完成配置文件的动态刷新。我们希望的是,当git仓库的文件更新时就能够实现动态刷新配置文件。要实现这个功能就需要Git仓库能够在配置文件更新后,自动调用Bus用于刷新配置的接口。那么要怎么实现这个功能呢?这就需要用到WebHooks了,好在码云和GitHub都支持WebHooks,我们只需要配置一下接口地址即可。这也是我们本小节需要演示的。
注:SpringCloud需要2.0.0以上的版本才开始支持码云的WebHooks,低版本对码云的WebHooks不兼容
首先打开仓库的管理界面,选择WebHooks,并点击右上角的添加:
然后输入相应的配置信息,注意这里不是配置/actuator/bus-refresh
接口了 ,而是配置 spring cloud config 里特定给WebHooks调用的/monitor
接口。至于域名,我这里使用了内网穿透的地址(natapp.cn获取):
添加完成后,点击右上角的测试,返回结果如下,则代表测试通过:
现在我们用之前的order-dev.yml配置文件进行一个测试,把env的值改为test,如下:
然后在不重启任何项目的情况下,访问之前打印env配置的接口。返回结果如下代表自定刷新成功了:
]
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。