夏言杰(夏森)
1、项目背景
目前海拍客采用Disconf作为配置中心用于配置相关的存储以及动态更新。其简单、实用的特点在一开始时能很好满足业务系统的需求,但是随着业务、系统的不断发展变得越来越复杂,Disconf本身只可以在配置修改时会一次性令所有依赖该配置的机器全部生效,有时候我们希望推送的配置能够只在部分机器生效,在被推送新配置的机器上观察新更新配置生效下的运行情况,再决定是否让配置在其他机器生效。这样如果修改的配置有问题时,则只会影响第一次推送的机器,也可以直接回滚配置。
在修改配置文件时,难免会产生文本编辑的错误,此时如果修改的是一些核心配置项容易引发大面积的报错从而产生大型故障!若使用灰度的方式,能先将配置在一台机器上验证,观察到错误后,及时回滚避免错误进一步扩大。
2、配置推送流程与灰度推送设计
disconf配置推送流程示意图:
在Disconf的基础架构数据流转图可以看出它的核心流程,应用通过监听ZK节点感知配置文件是否变更,在发生配置修改时,服务端修改配置,App触发ZK的监听事件之后便会有一个直接向服务端请求更新配置的动作,App主动拉取相关配置进行更新。
灰度推送初设计:
灰度核心流程本质上是选择灰度的机器配置值为灰度值,而其余机器则还是原先配置值就可以完成灰度推送的功能。为了产生”灰度“这一概念,首先用户在Web上感知配置使用机器的情况,其次是配置的时候存在灰度值和值的区别,这仅仅是表结构的变更,因为只有在灰度流程中才存在灰度值,灰度值有无就可以表示一个配置是否在灰度流程中。最后考虑服务端将机器的唯一识别标识持久化在Web端,这样同步的时候客户端也提供自己的唯一标识就可识别是否为灰度机器。
并且灰度过程中需要灰度继续、回滚、确定等功能。继续就可以只添加新的机器到灰度目标表,回滚时将灰度值,灰度目标表状态清空。确定时灰度状态表清空,配置值更新为灰度值即可。对比之前的推送是一种瞬时的发生,配置更新发生在瞬间,灰度则会存在一个过程,过程中通过机器的表现与预期对比进行进一步操作,则灰度是一个闭环的流程。
以上便是灰度功能的设计思路,可以由下图了解更多:
disconf灰度推送流程示意图:
在选择使用灰度推送时,Web端需要选择灰度生效机器,更新配置时应用会增加自身的实例指纹告知Web端,web端再根据gray_target表中的记录选择性将灰度值返回给被选择的灰度机器(m1),而其余机器还是收到之前值(value)。
3、详细设计
3.1 实例指纹
在架构中唯一标识disconf client端的概念,在监听zk时,将自身注册为临时节点,实例指纹的组成为:[hostname|ip][port][uuid]。因此可以通过zk获取一个配置下已注册机器列表,这样disconf client调用"配置更新接口"时传递实例指纹后,在web端就可以和灰度推送时选择的灰度目标进行匹配,识别出灰度目标机器。
3.2 状态控制
按照"一个完整的灰度过程一定是从正常态到灰度中,再回到正常态“的原则设计状态,在页面和服务内部在代码逻辑上应该加上相关判断,处于灰度中的配置不能再修改该配置,必须等到灰度流程结束才可以修改。
但是无需再添加一个字段作为灰度状态的标记,config表中可以通过grey_val字段是否为空判断当前配置是否正在处于灰度的流程中。下图展示了一个配置文件在灰度过程中的变化:
3.3 一些坏味道
在观察前面灰度推送的设计方案时有的读者可能已经看出来了,在disconf client端更新配置时,如果不是灰度目标的机器也会尝试更新配置,不过新更新的值和原值是相同的。因此整个灰度过程会有很多无用请求。(蚂蚁的drm配置中心,它的灰度是由服务端直接远程调用目标机器的接口,将值推过去,对其他非灰度的机器完全无副作用)。
但是目前这一种实现方案对Disconf来说二次开发成本较低,且中间件稳定性和可用性最为重要,在设计方案时其实是可以在Zookeeper中或者是客户端中进行一些操作,但是对Disconf自身的修改量是较大的,对于公司目前情况是需要承担的风险是过大的,读者如果有兴趣的话可以尝试相同思路尝试在ZK和客户端上进行一些操作来实现。
4、UI交互
灰度推送设计中修改了配置推送的核心流程,用户在交互时需要感知自己处于什么阶段,且能明确知道自身应用当前配置的生效情况,这样在使用Disconf才能达到安全推送配置的目的。
4.1 分批推送、回滚和确认
由于存在灰度流程流转的概念,当灰度推送开启之后,用户此时只可以选择之前还未选择的机器进行推送(图 4.1),且如果此时发现灰度机器状态不符合预期的话可以通过配置回滚将配置恢复到之前的稳定状态,如果配置符合预期并且其余机器无需验证可以通过确定按钮直接将配置更新为灰度值(图4.2)。
4.2 配置对比
当灰度推送功能开发后,配置从之前的正常、错误状态新增了灰度正常以及灰度错误的状态,在UI上新增状态栏表明配置是否在灰度,例如:当用户开启配置推送两台配置时,此时用户能获得的信息为其4台机器的配置都是OK的,并且其中两台被选择为灰度,正处于灰度的状态:
而当出现错误时,实例列表栏会说明几台错误,而配置的状态也会更新为错误,此时用户可以通过点击实力列表栏获取错误信息,实例列表中可以获得每一台机器上具体的值,状态栏给出字段说明错误信息,并表明错误类型是否为灰度错误,此时便可以区分是配置值是否是由于灰度失败造成的错误。此处灰度错误是由于该机器并未升级disconf版本不支持灰度推送功能导致错误。
5、使用场景推荐
a.分批推送,机器可能位于不同集群中,不同集群特点可能不同可以分批推进至不同集群。
b.灰度开关
由于灰度推送功能本身并无强制性,开发人员在修改配置时有时会觉得使用灰度推送的方式比较麻烦从而不走流程,这会大大降低安全性。为了配合公司项目落地,可以通过添加配置、应用层面上的标记,标记为核心应用/核心配置,标记后更新配置时只可以通过灰度的方式进行推送。被标记上的应用在推送时如果采用正常推送的方式会弹出下图的错误日志并退出。一开始使用时可以强制推进应用采用灰度推送,在大规模使用无误,且持续稳定后可以开放为配置维度标记,并开放打标功能供用户使用。
目前该情景已经在我司落地,选择了基础平台组中一批应用接入。目前已有20+应用升级Disconf接入。
后续可以将Disconf灰度推送功能与系统发布系统进行集成,共同保证系统稳定性。
6、总结
Disconf功能本身其实很简单,其中技术难度并没有太深,但是其十分重要,应用会将相关限流策略,开关,json配置存储在Disconf上,尤其Json格式的存储容易产生文本编辑错误。一些配置涉及线程数的更新,有的时候数据量较大可以将线程数增大加快处理数据。灰度推送可以作为一道屏障在更新上述配置时起到保护的作用。在项目开发完毕落地后,收到业务应用的接入请求,暂时先接入一些基础应用,在基础平台组内广泛推广覆盖了组内大部分应用,帮助各位Owner在推送配置时降低人为导致故障的可能性,灰度推送功能将Disconf成为稳定性建设中的一块稳定的基石。本文到此结束,感谢各位读者阅读!