转载自 什么是ABTest
在互联网公司的业务发展过程中,用户增长是永恒的主题,因为没有增长也就没有发展,所以在业务发展的早期产品迭代速度往往是越快越好,总之一句话:“怎么快怎么来”,至于系统建设得是否可以满足未来几年的扩展什么的,往往在用户增长面前都会显得很扯淡,因为慢了可能就死掉了。
而当业务发展到一定阶段后,野蛮生长的红利逐渐消退,用户增长空间在可见策略下变得不那么明显的情况下,如何合理地规划产品迭代策略就显得尤为重要了,而具体如何判断产品策略是否有效,往往就需要数据进行判断,其结果决定了该产品或策略的生命力以及与之配套的各类资源的调配,毕竟大部分公司是不会愿意将资源浪费在无效的产品和策略上的。那么,通过什么样的工具或手段才能确保数据驱动策略的有效落地和实施呢?
目前硅谷的很多公司都在通过ABTest及建设与之相适配的实验基础设施平台来实现这样的目标,而国内有条件的互联网公司也在逐步进行尝试。小码农目前所在的公司也在进行这样的尝试,作为比较前沿的一种思路与实践,虽然目前在国内的普及程度还并不是很高,但是作者相信随着国内互联网ToC流量红利的消退,这种工具会被越来越多的公司重视起来。本文将从基础理论及系统设计的角度与大家进行一些初步的探讨。
ABTest的目标&背景
在现实的产品设计场景中,我们经常会遇到多个设计方案的选择。例如,App或网页端某个页面的某个按钮的颜色是用蓝色还是红色,是放在左边还是右边?传统的解决方案通常是集体表决或由某位Leader拍板,类似的选择还有很多,从概率上很难保证传统的选择策略每次都是有效的,而ABTest显然是一种更加科学的方法。
ABTest,简单来说,就是为同一个产品目标制定两个方案(比如两个页面一个用红色的按钮、另一个用蓝色的按钮),让一部分用户使用A方案,另一部分用户使用B方案,然后通过日志记录用户的使用情况,并通过结构化的日志数据分析相关指标,如点击率、转化率等,从而得出那个方案更符合预期设计目标,并最终将全部流量切换至符合目标的方案。
上述的场景举例是比较简单的逻辑,而一旦业务进入深度精细化运营阶段,往往方案的比对会更加复杂,需要关注的指标也会越来越多,并且很多时候还需要同时验证多组策略,这里我们称之为实验。例如,在之前提到的UI设计策略中,如果需要同时验证按钮颜色(蓝色/红色)及位置(左/右)的效果,那么此时可组合策略有蓝色-左边、蓝色-右边、红色-左边、红色-右边,需要验证的指标有页面打开次数、下单成功率等等。此外,可能还有各种不同的业务逻辑需要设计不同的实验进行验证,如果通过硬编码去实施这种策略,会让事情变得很艰难,而难以推动,因为实施一次策略验证成本太高。
那么有没有一种方法和中间件系统来让事情变得简单而科学呢?答案是有的。
重叠实验基础设施
事实上,关于ABTest及数据驱动运营理念是被普遍接受的,而关键问题是在于如何实施与落地,不能落地的理论再好也是口号。Google作为全球互联网巨头,同时也是一家数据驱动的公司,在其产品迭代的方方面面都十分注重实验,几乎任何影响到用户体验的变化、包括可见的变化(如界面的改动),也包括更细节的变化(如不同的机器学习算法的改进)等都会设计不同的实验加以验证。
这方面Google公司走在了前列,而其发表的论文《Overlapping Experiment Infrastructure:More, Better, Faster Experimentation》(重叠实验:更多,更好,更快)更成为各大公司建设自身实验平台的基础参考。
在该论文中提出的实验基础设施的设计目标是:更多、更好、更快。因为在互联网产品迭代过程中,为了更快的进行迭代,产品或运营通常会要求同一个时间做N个实验,并且同一份流量在不同实验之间互不干扰,每个实验都能得到100%的流量。而要实现这些目标,不仅需要能运行更多实验的实验平台,也需要工具和持续的培训来支持更好、更快的实验,从而有效加快产品迭代的正确性与速度。关于以上三点论文中的具体阐述如下:
-
更多:我们需要系统具备一定的可伸缩性,以便于能够同时运行更多的实验。与此同时,也需要一定的灵活性:不同的实验需要不同的配置和不同的流量来衡量实验在统计意义上的效果显著性。有些实验只需要改变流量的一个子集,比如日本的流量,并且需要适当的调整流量大小;其他实验则可能会改变所有的流量,并在度量上产生较大的变化,因此可以在较少的流量上运行。
-
更好:无效的实验不应该允许在线上流量上运行。有效但糟糕的实验(如,线上Bug或无意中产生的非常糟糕的结果)应该能很快被发现并被禁止运行。标准化的实验指标应该对所有实验都是容易获取的,以便实验的比较是公平的:如两个实验在计算CTR(点击通过率)等指标时,应该使用相同的过滤器来去除机器人产生的流量。
-
更快:建立一个实验应该既简单又快速,简单到不需要专业的工程师,也不需要编写任何代码就就可以做到。评价指标应该很快就能被统计出来,以便快速评估实验效果。简单的迭代应该可以快速完成。此外,实验平台除了支持实验进行ABTest,还应该支持以易于理解的方式进行流量灰度。
那么具体应该如何构建一套实现上述目标的实验基础设施呢?在讨论具体的实施方案之前,我们还需要理解实验平台中几个重要的基础概念:
-
流量:即用户的访问,也是实验的样本来源。对流量的切分也是实验平台首先需要解决的关键问题之一。
-
参数:又称作实验变量,一个实验可能有多种策略或者模型需要在线上进行比较,这些模型或者策略就称作实验参数。
为了实现同时做更多的实验以及实现流量复用,需要将实验平台按照分层模型进行设计。关于分层模型有几个比较关键的概念:
-
域(domain):是指流量的一个划分,流量进入后首先划分域。
-
层(layer): 是系统参数的一个子集。
-
实验(experiment):是由零个或多个策略参数构成的,被用于改变传入请求处理方式的过程。
在以上三个关键定义中可以嵌套域和层。域包含层。层包含实验,也可以包含域。为了更好的理解它们之前的关系,我们可以分别看下其不同的设置关系:
(a)、三层的基本重叠设置
在图a中,我们简单地将参数划分为3个层。在这种情况下,每个请求将最多同时出现在三个实验中,每个实验都只能使用对应层的参数。
(b)、具有非重叠和重叠域的设置
在图b中,将流量划分为两个域,一个域是可以具有单个层的非重叠域,另一个域可以是具有三个层的重叠域。在这种情况下,每个请求首先被分配到非重叠或重叠域。如果请求在非重叠域中,那么请求最多在一个实验中,并且可以更改整个参数空间中的任何参数。如果请求在重叠域中,那么请求最多在三个实验中,每个实验只能使用对应层的参数。
虽然b这种嵌套方式看起来略微有点复杂,但它有几个优点。首先,拥有一个不重叠的域,可以允许我们进行一些需要改变大量通常不会同时使用的参数的实验。其次,这种嵌套可以允许我们进行不同的参数划分,例如,我们可以设想三个域:一个非重叠的,一个与参数分区重叠的,一个与参数分区不同的重叠域。最后,嵌套可以让我们更有效地使用空间,这取决于哪些分区最常用,以及哪些跨层参数实验最常用。
(c)、具有非重叠、重叠和启动域的设置
(d)、具有多个域的复杂设置
在图c/d中,展示了另外一个概念-启动层。启动层与前面讨论的实验层在几个关键方面有所不同:
-
启动层总是包含在默认域中(运行所有的流量)。
-
启动层是参数的独立分区,在域中,一个参数可以同时位于最多一个启动层和最多一个“正常”层。
-
为了使启动层与普通实验层之间的参数重叠工作,启动层中的实验有略微不同的语义。具体来说,启动层中的实验为参数提供了一个替代的默认值。换句话说,如果正常实验层中没有实验覆盖一个参数,那么在启动层实验中,使用指定的替代默认值,启动层实验的行为就像正常实验一样。相反,如果正常实验层中的实验确实覆盖了这个参数,那么这个实验就会覆盖参数的默认值,不管这个值是指定为系统默认值还是在启动层实验中指定的。
以这种方式定义启动层,可以允许我们在不干扰现有实验的情况下,逐步向所有用户推出更新,并以标准化的方式进行跟踪。启动层的一般用法是为每个启动特性创建一个新的启动层,并在功能完全展开时删除该层(并将新的参数值展开为默认值)。最后,因为启动层的实验通常比较大,所以它们可以用来测试特性之间的交互。
看到这里,大家心中是不是还充满了很多疑问呢?实际上,以上理论有点类似于我们在编程中学习的设计模式,是对经验和实践的总结和抽象,而至于采用什么样的设计模式,就取决于我们系统的复杂度和希望能够支持扩展的程度。在实际设计实验平台时,我们可以根据当前阶段业务的实际需要来进行分层模型的选择,下面我们就以图(b)具有非重叠和重叠域的设置为例,进行一些系统设计方面的讨论。
实验平台原理设计
我们以图(b)设置为系统分层模型参考,将流量划分为两个域,一个域只有一个单一层(非重叠域),和一个有三个层的重叠域。如下:
上述重叠域是一个三层实验,第一层UI Layer有三个实验参数:Red、Blue、Green。当在实验平台配置好参数及其流量(关于配置在后面的内容进行讨论),会按总计100桶(bucket)给三个参数分配各自的bucket区间,比如Red、Blue、Green的流量配置分别为80%、10%、10%,那么它们各自对应的bucket区间分别是0-79,80-89、90-99。后面Srch Layer,Ads Layer实验参数的配置以此类推。
在完成实验参数配置及流量设置后,各个实验参数有了对应的bucketId区间范围,那么对于用户访问流量又该如何进行分割,这里称之为分流,才能让不同的流量进入对应的bucket,从而执行相应的逻辑呢?
当流量进入后,实验分流服务可以根据不同的终端采用不同的用户标识id来hash分流,如web端采用cookieId,app端采用设备id,小程序端采用openId作为唯一分流标识符。在具体进行流量划分时,为了实现实验层流量划分的正交性,会将流量标识信息和实验层(Layer)标识一起进行试验流量bucket划分,实验层标识称为离散因子。如基于用户标识(uid)的流量划分:
bucketId=hash(uid,layer)%100
分流量原则上需要保证均匀性和一致性。均匀性是指流量唯一标识符在进行上述取模计算后均匀地落在每个区间。例如,将全站流量分成100份,那么uid%100的值为0~99,必须做到每个值分配的流量几乎相同。一致性是指某个流量唯一标识符取模的值是一定的,如某个流量的唯一标识符uid经过算法模块取模后的值为1,那么下次再经过算法取模的值还是1。上述划分流量中,采用的一致性hash算法就是为了确保上述两个特性。
通过上述内容的分析,我们了解了分流的逻辑算法,那么在代码层面这种划分方式具体又是怎样进行流量控制及ABTest的呢?
实际上,从理论上看实验平台及ABTest我们会觉得其非常复杂和深奥,但从实际的代码角度看,根据理论设计的模式规则、定义的实验以及为实验设计的参数指标等,最终的目的只是为了给业务代码提供优雅的逻辑判断方式,并在不需要业务逻辑关心的情况下,按照可统计、可分析方式进行日志的输出,并最终通过这些数据分析预定的指标、参数,从而得出实验或ABTest的结果(ABTest实际上是一种相对简单的实验,大家从概念上不要有困扰)。
具体来说,我们在实验平台定义一个试验(Exp)后,例如“界面实验(UI Layer)”会分别为其设置三组对照的实验参数,这里我们可以叫实验组(Group),Red组、Blue组、Green组。而为三个实验组的流量分配分别设置为80%,10%,10%,而该试验对应的层(Layer)的定义将全站流量划分为100bucket,所以根据这个配置Red组的bucket ID的范围为0-79,Blue组的bucket ID的范围为80-89,Green组的bucket ID的范围为90-99,而这些取值都是根据配置设置在实验组的配置数据中的。
当客户端或服务器端在进行ABTest时,需要引人实验平台提供的SDK代码包,并根据SDK提供的API进行实验逻辑编写,SDK会以无感知的方式拉取实验平台的配置,并缓存到本地进程中。在线上运行时,当流量进入后,会根据流量唯一标示(uid)并根据所要进行的试验,通过配置得到层(Layer)的定义信息,再通过hash算法计算该流量对应的bucket ID,最后SDK会提供一种优雅的判断方式来匹配对应的实验组,从而实现流量路由。此时业务端就可以执行对应对照组的代码逻辑了,如果对照组中还设置了相应的策略参数,也可以根据策略参数进行进一步的策略逻辑判断。
而SDK会根据实验逻辑向日志系统自动上报实验日志数据,实验平台根据上报的数据按照实验关联的指标进行分析,并进行展示。流程如下:
在上述流程中,我们了解了利用实验平台开启一个实验的基本步骤及逻辑。在大部分情况下,简单的ABTest或流量灰度利用单层非重叠实验就可以完成了;而如果业务需要进行复杂的多层重叠实验,为了实现流量复用,我们在客户端或服务端编写实验逻辑时,需要注意不要让多个实验互相干扰。
后记
要设计好实验平台,需要进行很多细致的工作,功能上看需要进行实验管理、流量管理而这往往需要设计一套简单易于操作的配置界面,从而允许用户对实验进行配置管理,并对实验参数进行便捷的流量分配。
上报的大量实验数据需要收集和存储,需要一套相对完整的日志收集系统,为了方便指标分析,我们还需要将实验数据存储到Hadoop集群,并提供快速的数据分析体系。除此之外,还有诸如配置分发,客户端ABTest重启等。希望大家能在实践中处理好这些细节问题,从而实现更多、更快、更好地实验目标。