配置管理中心小结

上一篇文章介绍了自己练手写的配置管理中心,在这篇文章里记录下其中用到的一些技术原理。

Zookeeper相关

实时动态更新配置

应用除了能够从配置中心读取配置,还有一个核心功能是监听配置的改变,从而实现不需要重启来实时动态更新配置。
实现方式就是利用Zookeeper的Watch来监听配置,Zookeeper有2个后台线程:SendThread,EventThread。

zookeeper-interaction.jpg

SendThread:IO和心跳线程, 用于处理Zookeeper Client和Server间的Request和Response
EventThread:事件处理线程,用于处理Zookeeper的事件,比如连接状态改变,Watch事件。
收到Watcher Event的时候会联系WatcherManager找到相对应的Watcher,从WatcherManager里面移除这个Watcher(因为每个Watcher只会被通知一次) 并回调Watcher的process函数

Zookeeper原生客户端和Curator不同的处理方式

相对来说,Curator提供了更方便的API,而且帮助处理了很多本来需要自己考虑的情况,所以使用起来更加便利。

  1. 连接状态的管理,如果Zookeeper客户端连接断开,会主动和集群中其他服务器连接。
    若在Session Timeout前连上了,一般不需要处理,临时节点和Watch都会存在,如果超过了Session Timeout,客户端会Expire,失效。
    如果使用原生的客户端,是需要自己重建客户端的,Curator的话会帮助我们做这个事。

  2. Zookeeper的Watch是一次性的,如果要一直监听配置的改变,需要不断的设置Watch。
    如果使用原生的Zookeeper客户端,这段逻辑需要自己完成,Curator提供了现成的NodeCache。

  3. 临时节点的处理,一般在CONNECTED(连接)或者RECONNECTED(重连)事件中判断临时节点是否存在,不存在就创建。
    有一种特殊情况是:应用异常终止后立即重启,导致旧的Zookeeper客户端没有调用close方法来关闭Session,在Session Timeout内,新的客户端又启动了,但旧客户端的临时节点还存在,
    新的客户端便不会创建。当旧客户端Session Timeout后,临时节点就销毁了。 对于这种情况,需要比较当前SessionId和上次的SessionId,如果不一致,就需要将临时节点销毁重建。

Spring相关

项目提供了spring-boot-starter-configuration-center库,和Spring集成,提供@Config注解来实现配置的获取和自动更新。

spring-lifecycle.png
上图是Spring Bean的生命周期,如果要满足我们的需求,有2种方式。

第一种:基于BeanFactoryPostProcessor
Spring从3.1版本开始增加了ConfigurableEnvironmentPropertySource

  • ConfigurableEnvironment
    Spring的ApplicationContext会包含一个Environment(实现ConfigurableEnvironment接口)
    ConfigurableEnvironment自身包含了很多个PropertySource
  • PropertySource
    属性源,可以理解为很多个Key - Value的属性配置

所以可以实现BeanFactoryPostProcessor,在应用启动阶段,从Zookeeper读取所有的配置,组装程PropertySource,插入到Environment中
spring-bean-factory-post-processor.png

第二种:基于BeanPostProcessor
此方法参考@Value注解的实现方式,实现BeanPostProcessor,在Bean的初始化完成后,从Zookeeper获取配置,注入属性。

Apollo项目就是使用的第一种方式。我这里需要用第二种方式才满足需求,因为我想要使用@Config(refresh=true)注解的Field能Watch配置更新来反射修改, 所以需要Field的对象先实例化出来。

容灾

配置中心不应该是一个被Application强依赖的服务,它的状态不应该阻止Application的启动。即使配置中心挂了,Application应该也可以正常启动起来,configuration-center里面用到了如下的容灾策略。

  1. 本地内存缓存,当Application运行时与配置中心的连接丢失或配置中心完全宕机,仍能正常地调用服务。

  2. 本地缓存文件,当应用与配置中心发生网络分区或配置中心完全宕机后,应用进行了重启操作,内存里没有数据,此时应用可以通过读取本地缓存文件的数据来获取到最后一次订阅到的配置。

  3. 本地容灾文件夹。正常的情况下,容灾文件夹内是没有内容的。当服务端完全宕机且长时间不能恢复,同时服务提供者又发生了很大的变更时,可以通过在容灾文件夹内添加文件的方式来开启本地容灾。此时客户端会忽略原有的本地缓存文件,只从本地容灾文件中读取配置

参考文档

Zookeeper Guide
Apollo
Zookeeper使用注意点
Failover
Spring Bean Lifecycle
Curator