在阿布去年进行召回引擎开发时,涉及到了一个远程配置的拉取功能,为了 mvp 流程的尽快上线,当时使用了最易实现的单版本模式,就是把 场景、渠道、索引、关联信息 等配置存储到 mysql 表中,且只有实时的一份数据。
关于动态配置的获取,有两种思路,1、配置实时拉取,即使用时进行实时的配置查询;2、配置的动态下发,即配置发生变更时注入本地缓存,使用时查询缓存。各位读者朋友,你们觉得应该使用哪一种思路呢?
单版本模式的缺点是显而易见的,随着阿布开发的召回引擎越来越重要,承接了越来越高的流量,当老板知道当前引擎强依赖的配置竟然没有备份,且无法回滚时,是非常震惊的(虽然阿布早就跟老板说过这一点),责令阿布尽快开发配置的版本能力,实现配置的多版本、可回滚、可追溯等功能。
激烈的讨论
作为一个组内的小卡拉米,阿布当然要把组内的大佬发动起来,群策群力,听取大家的方案,同时也把自己的方案摆出来,让大家批斗一下。大家也都很给力,讨论的过程异常激烈,会议室的门都要飞起来了(怀念当时组内的氛围,后面阿布换组后,再也没这种盛况了)。为了本文的篇幅,阿布就只简单总结一下各位大佬的方案,讨论的过程就略过了。
阿磊的方案
阿磊首先是从发布的角度来考虑的。对于召回引擎来说,修改线上配置的时间点一般是需求上线,而需求上线的流程首先是新建 release 分支,然后经过预发、灰度、生产环节,最后 release 分支代码合并至 master,需求完成发布。因此,阿磊认为应该将配置与分支进行绑定,即每一个分支对应 1~n 个版本。
配置更新时,获取当前的 release 分支,单独的配置版本记录表将 分支-配置版本号-配置记录ID 关联关系存储下来,配置快照表将当前配置存储为快照进行归档。
配置获取时,首先查询当前的 release 分支,再从配置版本记录表中查询配置记录ID,再根据配置的记录ID去快照表中获取配置数据。
阿磊是组内公认的架构师,思考问题比较全面,但是大家认为方案的复杂度比较高,与发布分支的关联关系让大家理解比较困难。
阿布的方案
阿布认为当前召回引擎已经承接了非常大的流量,应该进行最小改动。反对新增快照表进行不同版本配置的存储,而是应该采用配置的染色法,在当前的配置表中都新增一个版本字段。
配置更新时,判断当前的配置版本数量,如果只有一个版本,那么进行配置的新增。如果有两个版本,那么移除最老的版本,再进行配置的新增。
配置获取时,默认进行最新版本配置的获取,当配置需要回滚,整体移除新版本配置,下发老版本配置。
大家都认为阿布的方案脱裤子放屁,实际上也是快照的方案,将快照数据与基础的配置数据揉到一块,让数据更加混乱,而且只能进行两个版本的切换,只具有着有限的追溯与回滚能力。大家都笑话起了阿布,空气中充满了快活的空气。
最终方案
经过了数次的方案讨论会议,最终敲定了比较简单,符合当前业务需求的方案。
快照表是必要的,由于召回引擎的单个版本配置并不是非常大,因此预计在较长时间内,单张表完全可以承载记录配置快照的诉求。同时新增配置基础表,表中的 status 标识配置的预发、灰度、生产状态,valid 字段标识配置是否有效。配置基础表与快照表通过配置ID进行关联。
配置更新时,将全量配置新增到配置的快照表中,基础表中新增该配置的一条记录,同时根据该配置更新时约定的状态,例如,本配置为灰度配置,那么就将配置基础表中该配置的 status 置为灰度。需要注意的是,相同状态的配置只能存在一个,当配置发生更新时,就会根据当前配置的状态,将其它同状态的配置置为无效。
注意,定义配置的更新动作为:开发同学完成了本次需求全部配置的修改,然后触发这一揽子更新。
配置获取时,需要根据不同容器节点的状态进行下发,如果当前容器节点处于灰度状态,那么就去寻找灰度配置下发,如果处于生产状态,就会寻找生产状态的配置进行下发。
配置回滚时,拉取历史配置并选择下发,同时将其它同状态的配置置为无效。
预发/灰度验证时,将新增的配置置为预发/灰度状态,配置下发完成后,预发/灰度容器就获取到了新的配置,而且不影响生产。
当发布从灰度切到生产,配置的状态也需要从灰度变更为生产,确保启动后的生产容器能够读到最新的配置。
结语
在阿布的辛苦劳累挑灯夜战下,配置版本化功能如期上线了,支持配置的多版本、多状态,支持了可追溯、可回滚能力,无论是预发、灰度或是单个节点,都支持配置的下发验证。老板很高兴很满意,对阿布说:"多亏了阿磊啊,你当时的方案就是个乐子!"。