导读:大型互联网公司推出新功能之前,会选择一小部分用户进行灰度及 A/B 测试,并根据这些反馈对功能进行改进。知名的有 facebook 的 Gatekeeper,LinkedIn 的 XLNT 等,最近 Dropbox 也公布了其灰度发布平台。本文由魏佳翻译,转载请注明来自高可用架构。
像 Dropbox 这样的 SaaS 公司需要持续升级迭代他们的系统,并且这会涉及整个架构栈的所有层。当需要调整某些基础架构,发布一个新功能,或是设置 A/B 测试时,最重要的是我们如何快速变更并体现在产品中。
我们想要把一些可配置的 “开关” 添加到我们的产品中,并且根据我们的需要来动态打开或关闭。这能带给我们很好的灵活性,以及安全的实时的调整能力。
为了满足这种需要,我们构建了一个名为 Stormcrow 的平台,它允许我们编辑和部署 “feature gates”(可以称作功能门或开关)。它是一个可配置的代码路径,通过请求 Stormcrow 来确定如何执行。典型的代码使用看起来像这样:
可在更改后10分钟内于生产环境生效。
可用于所有 Dropbox 系统,从底层的基础架构到桌面版或移动版产品。
提供高级的用户投放功能,比如可以根据我们数据仓库中的用户画像来细分用户。
构建一个像这样通用的功能开关系统并不容易,因为它需要具有足够的表达或描述能力来处理不同的用例,同时要足够健壮来应对 Dropbox 巨大的流量。 接下来就让我一一描述系统的工作原理和我们的一些经验教训。
示例
假设我们想执行一项 A/B 测试,看看德国用户喜欢什么颜色的按钮。 进一步,假设我们已经知道英语为母语的用户喜欢蓝色按钮。那么在 Stormcrow UI 中,我们可以这样配置功能:
这表明我们将对“德语区域的用户”分别以 33% 和 33% 的比例显示红色按钮(RED_BUTTON)和蓝色按钮(BLUE_BUTTON),剩余 34% 的用户则不显示该按钮。同时,使用英语会话(译者注,指浏览器语言或客户端语言)的用户则 100% 显示蓝色按钮(BLUE_BUTTON)。除此之外的所有剩余用户并不参与这项 A/B 测试。
如何定义群体?
要了解群体是如何定义的,我们需要了解两个概念:
选择器(selector)是一个代码对象,它被传递进 Stormcrow 以帮助它做出判断。例如,
user
和session
对象都可以用作选择器。数据字段(datafield)是一段代码,它接收一个或多个选择器,并提取指定类型的值:布尔值、日期、数字、集合或字符串。 然后将它们通过简单的规则引擎(使用这些值执行逻辑计算)组合成数据字段。
这里是一个真实的数据字段例子,user_email
:
@dataField
装饰器(decorator)指定该数据字段需要一个 USER
对象,并且将产生一个 STRING
。 它还包括一段帮助文本,由此我们可以自动生成文档。函数的实际主体只是将用户的电子邮件从对象中取出。
tomm@dropbox.com 这个用户:
因为可以运行任意逻辑计算,所以数据字段十分强大。在 Dropbox 内部定义了很多数据字段,来支持我们所有的用例,不通的团队如果需要他们可以不断得添加新的数据字段。
基于 Hive 的群体分类:连接我们的分析数据仓库
即使具有创建任意数据字段的能力,我们也面临一个限制:我们只能依赖我们服务器代码可访问的信息(来定义群体),也就是已经加载的模型或数据库中。但是 Dropbox 还有另一个大数据源:我们基于 Hive 的分析数据仓库。有时候 Dropboxer 想要通过写一个 HiveQL 来查询一组任意的用户,这就可以利用各种历史日志和分析数据。
派生群体:从简单的群体定义中构建复杂群体
Stormcrow 最强大的功能之一是定义群体的能力。比如派生群体,下面示例是一个群体,它匹配 a)“Android设备”用户和 b)功能 recents_web_comments
值为 OFF。
这个功能帮我们避免了有些复杂匹配规则不断得被复制和粘贴。相反,Dropbox 的功能开关旨在构建一组核心的基本群体,可以混合和匹配以满足任意复杂的匹配需求。我们在实践中发现,设计派生群体层次结构与重构代码非常相似。if
” 语句,以便在实验之间进行选择。而不是写形如“如果用户匹配在实验 A 中就显示东西 A,否则如果匹配在实验 B 中就显示东西 B”这样的逻辑。
选择器推断:通过推断附加信息使得 API 更易于使用
像其他复杂的软件系统一样,我们的代码中使用了很多 Dropbox 内部模型。例如,user
模型表示单个用户帐户,team
模型表示 Dropbox 业务团队。 identity
模型代表配对的帐户:它将个人和商业用户模型绑定到单个对象中。我们所有的模型都通过各种一对多和多对一的关系连接。u
并且希望查询针对团队而开关的功能。 他们可以这样写:
Stormcrow 自动推断来获取更多的信息,所以开发人员只需要写:
在 Stormcrow 中,我们将 Dropbox 的模型关系表示成一个图,我们称之为选择器推断图。在这个图中,每个节点都是模型类型,从节点 A 到节点 B 的边意味着我们可以从模型 A 推断除模型 B。当 Stormcrow 调用时,我们做的第一件事是获取指定的选择器,接着在图中计算其传递闭包(transitive closure)。thunk,它们会被延迟求解(evaluate),这样我们只有在实际需要选择器来作出开关决策时才计算它们。 请参阅下面的“性能风险”viewer
是一个非常方便的模型,因为我们可以使用它来推断 session
,team
,user
和 identity
。
我们发现选择器推断为开发人员带来了巨大便利,同时易于理解。当然我们也有检查工具来确保开发人员不会传递错误的选择器。请参阅后面的“审核挑战”
部署:Web 和内部基础设施
如果你有大量生产服务器,如何将功能门控的配置部署到它们上面呢?很显然,我们需要将功能门控相关的数据保存在数据库中,但是那么就需要一次网络调用来检索。dropbox.com 上一次典型的页面加载中可能会涉及大量的功能门控,这会导致对数据库的大量读取。即使使用精心设计的缓存系统(例如使用本地缓存+ memcached)缓解这些问题,数据库也会成为系统的单点故障。stormcrow_config.json
的 JSON 文件部署到所有的生产服务器上。这个部署仅仅使用我们的内部推送系统,并且在每次对 Stormcrow 配置进行更改时推送。
我们所有的服务器都运行一个称为“Stormcrow 加载器”的后台线程,它监视磁盘上的 stormcrow_config.json
副本,当它改变时就重新加载它。这让 Stormcrow 不用中断服务器就可以重新加载。
部署:桌面端和移动端
对桌面版和移动版的功能开关稍有不同。对于这些客户端,它们通常是批量请求开关相关的信息。比如从后端获得的 Stormcrow:
这两种平台上的客户端还会传递一个或多个包含平台特定信息的特殊选择器。移动客户端传递一个选择器,提供关于正在使用的 App 和设备本身的信息。桌面客户端则传递一个带有桌面主机信息的选择器。与其他选择器一样,Stormcrow 有可根据这些平台特殊的选择器来定义规则的数据字段。
监控
Stormcrow 中所有被开关的功能的每次分配和曝光,都会记录到我们的实时监控系统 Vortex 中。 Stormcrow UI 中嵌入了图表,用户可以利用其来跟踪分配和曝光的速率。例如,下图显示了三种不同的变量(黄色,蓝色和绿色),以及每个变量随时间曝光给用户的数量。 每次修改功能(或功能所依赖的群体)时,图表中会用垂直线注释。这使我们很容易地看到变更的影响。在该图中,我们可以看到绿色和蓝色变量在第一次修改之后收敛(垂直线),同时黄色变量上升。
用户还可以单击底部的链接,使用我们的 Vortex 或其他数据工具更详细地挖掘数据。
性能风险
由于 Stormcrow 的模块化数据字段设计,Dropbox 的开发人员可能直接或间接得编写严重影响性能的数据字段。比如:有人创建一个新的数据字段,对于他们的小型业务来说是非常安全的,但这个数据字段也可被其他人使用,这就可能造成小型业务系统无法承载大量的请求流量。
审计挑战
功能开关有一方面比较棘手,因为它们没有被纳入版本控制中:它们可以独立于使用方代码进行更改。通过我们的“每日推送”系统(对于我们的后端)或通过桌面版或移动版客户端的发布过程,Dropbox 中的代码上线以可预测的方式进行。 但对于功能开关的变更,由于它们的性质,可以发生在白天或晚上的任何时间。因此,拥有完善的审计工具很重要,因为我们可以尽可能快地跟踪功能开关相关的回归。
对代码库的静态分析更有趣。我们运行一个名为“Stormcrow 静态分析器”的特殊服务。 它会拉取我们的代码并扫描它,搜索 Stormcrow 相关功能的使用。 对于给定的需要开关的功能,它会生成:
一个当前 master branch 中所有出现此功能的列表。
一个“历史视图”,展示了此功能相关的所有提交记录。
例如,下面是静态分析器对一个名为 can_see_weathervane
功能的输出:
静态分析器还会执行另一项重要的任务,那就是,我们的生产代码中找到的与单元测试正在测试相匹配的变量。 它会发送“nag”邮件给该功能的所有者告知相关问题,比如已经弃用的功能应该从代码库中删除。
质量保障和测试
总结
为什么新的平台称为 Stormcrow?因为这个系统取代了我们以前的功能开关系统 Gandalf(译者注,甘道夫会说“你不能通过!”) ,同时指环王的粉丝们会将“风暴”(Stormcrow)视为甘道夫的名字之一。
英文原文
https://blogs.dropbox.com/tech/2017/03/introducing-stormcrow/
推荐阅读
本文由魏佳翻译,转载请注明来自高可用架构,欢迎加入国外优秀架构文献翻译小组,可以通过公众号菜单「联系我们」了解详情。
高可用架构
改变互联网的构建方式
长按二维码 关注「高可用架构」公众号