原理
在Horizon平台的设计之初我们就引入了Spring Cloud Bus用于支撑配置的动态刷新。这项技术是基于消息队列服务来实现的,简单来说,Spring Cloud Bus使用一个消息队列服务形成一个消息总线,每个需要获取配置的客户端都将与消息总线连接,获得各自独立的一个Channel,而配置中心则是负责通过消息总线通知所有客户端获取最新的配置。大致是如下这么个流向:
这里由于配置中心需要通知所有客户端最新配置,因此,配置中心还需要从注册中心获取注册服务的详情。
而之所以使用消息队列服务是因为,消息队列服务本身支持“发布”–“订阅”模式,在配置中心发布新配置后,将把这个动作广播给所有的订阅者,从而通知他们执行配置更新。
配置
我们这里没有选择Kafka,而是选择了RabbitMQ,是出于如下考虑:
1、Kafka依赖zookeeper,而rabbitmq可以独立部署
2、Kafka虽然吞吐量较RabbitMQ更大,但RabbitMQ的单一消息可靠性比Kafka更高。
3、由于配置刷新是吞吐量非常低的操作,可靠性>性能
在每一个客户端都配置了消息总线的地址,并且引入了Spring-Cloud-Config-Client的依赖之后,每个客户端都会与消息总线建立起如下连接:
同样地,配置中心本身也需要实现一个动态刷新,但具体要实现的不是动态刷新功能,而是向外界暴露一个动态刷新的入口,这样,可以在配置变更之后第一时间来调用这个接口完成刷新。这个接口已经预先定义好了,需要在Spring Boot Actuator中暴露一些端点:
management: endpoints: web: exposure: include: bus-refresh,bus-env,health,info
需要暴露出的是/bus-refresh和/bus-env两个端点。在暴露之后,通过HTTP POST来调用如下端点:
http://127.0.0.1:7011/actuator/bus-refresh
当然,在调用时需要按照实际场景加上身份验证信息。
实践
来看看我们调用这个端点执行刷新之后会发生什么吧。
在9点44分我们修改了zuul-service的配置并执行了端点调用:
服务器返回了一个204的状态码,表示成功,但无需返回任何内容。
来看日志中心中的内容:
zuul-service立即开始进行配置重载,而且配置重载的速度非常快,两台服务器的zuul-service分别花了1.273秒和3.357秒完成重载,并且,在后面的日志中,可以看到详细的配置被刷新的记录:
简单叙述一下触发端点之后客户端的动作:
1、客户端接收到消息总线下发的消息,从配置中心重新获取配置
2、热加载配置
3、重新注册自身服务到注册中心
小结
之所以引入这个配置热刷新的机制,仍然是为了减少运维的工作量。如果没有这个配置热刷新的功能,每一个服务的配置变更后,运维人员都要登录对应的服务器来手动停止并重新启动服务,不仅耗费人力,也降低了服务稳定性。通过这种热刷新机制,通过调用配置中心的端点就可以实现对所有服务配置的自动刷新,在配置有较大修改的时候可以极大省去运维工作。除此之外,也可以与BitBucket等Git仓库进行WebHook集成,实现配置提交/合并时就自动刷新,进一步解放双手,提升生产力。