Categories
程式開發

携程是如何做AB实验分流的


一、背景

携程是业界比较早进行AB实验的公司。AB实验可以简单认为是传入一个实验号和用户分流ID到AB实验分流器,分流器吐出分流版本A、B、C、D等,通过截取应用流量落地一段时间的分流数据,就可以分析具体版本的优劣,决定启用新版本或者沿用老版本。

携程的AB分流器沿用至今,在业务发展上发挥了很大作用,但也存在一些问题。

1)携程内部,除了携程App,还有小程序、Online页面等都在用AB实验分流器,这些分流器是不同部门维护的不同接口,导致AB实验人员在开发的时候,有时候会用错,或者经过几轮沟通才能找到适合的分流器接口;

2)AB实验分流器在公司越来越多的AB实验应用接入的时候,响应效率不尽人意,没有开始的时候那么好。还有实验新配置的分流规则,在一个访问量大的页面如携程App酒店主页上很难即时生效,有时候要等到凌晨访问量较少时才生效;

3)AB实验方法论也需要改进,从而更精确地指导AB实验结论。但AB实验分流器前端接口里直接引用了AB实验配置表的全量字段信息,导致AB实验配置表随着AB实验方法论改进更新的时候,AB实验分流器也需要更新换代,这对公司的各个实验应用方来说是不可接受的。

基于此,我们开始着手携程AB实验分流器的改进。AB实验分流器的效率改进是重中之重,收口公司众多的分流器接口,迁移旧接口流量到新接口和推进公司AB实验应用采用新分流接口,这样才可以适应AB新方法论上的AB实验配置的更新迭代。

二、改进结果

截至到目前,除少量在2020年年底计划下线的.net应用外,其他的应用都通过公司的slbportal工具把分流流量迁移到改进过的新AB实验分流器接口,或者直接采用了新AB实验分流器。下面贴上新旧AB实验分流器的改进效果,供大家参考。

携程是如何做AB实验分流的 1

从以上的流量统计图可以看出,新AB实验分流器在QPS相应更大的情况下(200.7->290.2),P99.9线反而表现的更好(363.1ms->5.2ms)。可见新AB分流器的响应更快,对旧AB实验分流器接口的效率改进还是比较显著的。

三、改进方案

本文将从AB实验分流器整体设计,收口,SDK设计和分流器后台选型设计方面进行分享,主要说明如何提升AB分流器的分流效率,希望给AB实验特别是AB实验分流器的开发人员带来一定的启发和帮助。

3.1 AB分流器整体设计

AB分流器整体设计是用SDK还是service方式,是一开始就要制定的,因为如果方向搞错,后面都要重新来。

采用service有改动和运维方便等优点,但考虑到全公司都在使用AB分流器,如果用service方式,除了网络访问service影响分流效率外,携程用户的每台手机,每个pc和小程序页面等都可能调用到这个service,对service的冲击还是很大的。

一个访问量很大的AB实验页面,也会影响到其他访问量相对小的AB实验页面,这也是不公平的。所以用驻留SDK的方式,把AB实验分流器分发到各个部门的各个AB实验应用中,让各个部门自行根据AB实验流量调配资源,分流效率也可以最大化。

携程是如何做AB实验分流的 2

3.2 AB实验分流器收口

文章开头提到携程AB实验几乎在用户能用到的携程产品上无处不在,携程App、小程序等,这些AB实验调用的是不同部门开发的不同的AB分流器。

AB实验最重要的是两个口子,一个入口是AB实验分流器,一个出口是AB实验分析报表,入口要进的简单,出口要出的明白。收口这些众多的分流器接口到一两个简单接口,对AB实验开发人员和AB分流器的开发维护都是有利的。

下图概括了AB实验分流主要接口的收口工作(左边是旧分流器接口,右边是新分流器接口):

携程是如何做AB实验分流的 3

3.3 AB实验分流器SDK设计

分流器收口的效果是显而易见的,原来需要跨部门多个接口沟通解决的事情,现在一个部门一个接口就可以了,开发测试也方便。

新分流器SDK完全兼容旧分流器接口的业务功能,并做了一个主要的技术改进,从“胖”SDK变成“瘦”SDK。

旧SDK中,当一个实验分流请求过来后,会关联查询缓存里实验的各种AB实验表信息,如实验域、实验层、分流规则(分流桶)和指定版本等信息,然后计算一个分流版本信息返回。

新SDK缓存里只有一个类似AB实验宽表的信息存在,这个宽表是影响实验分流的各个字段信息的最小集,去除了旧SKD中的对分流结果无影响的分流频道等字段信息。最小集定义好后,基本就固定不变了,旧SDK里的关联查询动作在新SDK里推到分流器后台去做。

上述最小集宽表的存在,让AB实验系统在改进AB实验方法论后进行的不断迭代开发过程中,不用频繁替换AB实验应用的分流器。因为、新AB分流器后台会提前关联查询,组织好宽表数据提供给前端的分流器SDK使用就可以了。

上述的减肥操作让分流器SDK的效率提高一大截。另外旧分流器SDK的实验缓存没有读写分离的概念,当AB实验页面,如携程App酒店主页有大量并发请求过来的时候,有可能会导致AB实验新配置的分流规则或者指定版本等很长时间不生效,新AB分流器SDK缓存引入了CopyOnWrite的设计,让影响到分流的AB实验改动能够快速生效。

3.4 AB实验分流器后台选型设计

AB实验业务特点是读多写少的,写有单个数据的写入,也有批量数据的写入,采用CopyOnWrite设计可以很好地支撑这种场景,后面讲到的分流器后台分布式缓存系统也采用了类似的设计。

旧AB实验分流器后台通过SOA服务直接读取DB里的AB实验分流配置信息,会让DB成为AB实验分流的瓶颈。SOA服务可以根据分流器请求的流量自动扩容缩容,但DB不是。DBA看到复杂的sql查询,还有这么多的访问量的时候,也是不允许的。

所以新AB实验分流器后台需要在DB前面多加一层前置的数据缓存系统来提高分流效率,这个缓存系统是采用公司成熟的qconfig还是redis,或者结合AB实验特点自己部署一个分布式缓存系统呢?

AB实验通用的业务操作是对一个实验进行用户分流,也有对同一类型的实验进行分流,如携程App对这个App版本下的所有App页面端实验进行分流,这也是为分流效率考虑的。

qconfig可以进行简单配置数据的实时推送,对于AB实验这样稍显复杂并且是大批量的关系型数据是不太适合的。举例来说,一个携程App上的AB实验分流器需要拿到所有手机页面进行的实验,是在qconfig上一个配置文件中配这些所有实验,还是每个实验一个配置文件?

单一一个配置文件会让携程App访问公司qconfig服务器成为一个很大的IO操作,多个配置文件会让携程App收到这些改动的实验配置信息后,还要进行聚合操作。qconfig中会存在一个“长连接”来进行实时配置信息推送,每个AB实验应用的多个设备上都会建立一个和AB实验分流后台qconfig服务器上的这样的连接。“长连接”是很难适时根据流量进行扩容和重连的,公司的灾备演练过程中出现的apollo和qconfig配置系统负载过高就说明了这一点。因此新AB实验分流器后台的设计中首先排除了qconfig这一方案。

redis在公司和业界用的比较成熟,采用redis如出现数据问题,可以给到公司的redis框架部门解决。但任何设计都是为业务服务的,如果一个流行的方案不适合现在的业务,那就要考虑改进或者自行设计了。

还以携程App页面端实验分流为例,可以把app页面端单个实验的名称作为redis的key,value里存影响实验分流的关联字段信息。当更新一个或者多个app页面端实验,或删除一个或者多个过期的app页面端实验的时候,批量读取app页面端实验就会产生不一致的现象。

如果把这些批量的app页面端实验分流信息组合放在一个key对应的value里,这个key的读取效率就会很差,会影响到其他类型单个实验信息的读取。AB实验分流的字段信息比较多,就一个AB实验指定版本varchar字段已经定义为20000还不能满足某些部门的需求,可以想象多个实验分流放在一个value里, size会有可能很大。

AB实验分流的一致性设计要求是要高于时效性的,可以晚一点拿到最新的分流规则,但同一时间读取到的实验分流应该是一致的,这对于AB实验报表分析也是有利的。

综上所述,redis不大适合AB实验分流,其分布一致性hash也未必能满足特定的AB实验业务数据扩展的需求,在其上改动的成本也大。所以我们在apache ignite的基础上开发了一套分布式缓存系统,满足实时性、一致性、高并发、高性能、高可用的需求。

这套分布式缓存系统可以走公司paas发布系统发布,系统节点可以纳入公司的监控告警系统,可以水平扩展,可以以key-value的形式写入annotation标记过的java object,以符合ANSI-99语法的sql语句读出,一个个分布式缓存节点发布的时候不影响缓存一致性的读取。AB实验分流器后台部署图如下:

携程是如何做AB实验分流的 4

上端是SOA service供AB分流器调用,中间是分布式缓存系统,下端就是AB实验配置数据库。

AB实验分流系统后台取数据的概要设计如下:

携程是如何做AB实验分流的 5

上图的分布式缓存系统部署有一个snapshot service,这个service负责每5分钟关联生成分流信息宽表,把可写cache清空,然后把分流信息宽表的全量数据写入。写入完成后会把可写cache标成可读cache,可读cache标成可写cache,每次soa访问分布式缓存系统的时候,会先从snapshot service里检查哪个cache是可写的,然后从可写cache中读数据,可读和可写cache的数据有效期都设置成一天。

Snapshot service这种设计可以避免前面redis方案中提到的批量数据一致性的问题,效率上也是好的,相当于读写分离。可以认为snapshot service是分布式缓存系统的数据自治中心,在分布式系统重启的时候,还能自动从DB中再拉取组织数据。这种设计还有别于通用的缓存设计cache aside, read/write through和write behind三种设计。

AB实验分流系统后台实时更新数据的概要设计如下:

携程是如何做AB实验分流的 6

上图设计可以让分流实验数据改动后实时在分流器中生效,而不是在分布式缓存系统5分钟后更新全量分流宽表信息后才生效。注意在设计中没有采用用消息包里放改动的实验分流信息,让SOA service收到消息后立即改动对应实验,而是SOA service收到消息后,再重新以拉的方式读一遍数据。通过一种方式更改数据比通过多种方式更改数据更安全,检查问题也方便,同时也能聚合并发的消息再拉取。

四、后序

携程AB实验分流器的改进和设计大致情况如上所述。目前改进的新AB实验分流器和分流器后台在公司的几次灾备演练中表现的很稳定。分布式系统在开发的时候遇到过分布式唯一标示控制和读取的问题,在部署分布式系统时遇到过snapshot service重复部署的问题等,这些都一一解决了。

在公司灾备演练切换集群网络的过程中,出现过后台的分布式缓存系统无法从单点系统恢复成多点系统的问题,这可能是分布式系统的共病。因为掉线的节点数据的一致性校验是很繁琐的,这时候需要手工重启下掉线的分布节点。

AB分流器设计还有很多需要完善的地方,譬如实时缓存监控和告警等,路还没走完,要眼望前方,同时要时不时回头看看,总结提高。

作者介绍

Will Wang,携程技术专家,负责AB实验分流和其他数据智能项目的开发。关注大数据和分布式方面,会做一些深入的开发部署和结合业务数据的基准调试工作。

本文转载自公众号携程技术(ID:ctriptech)。

原文链接

https://mp.weixin.qq.com/s/yleskA9beaSCpFVD4uroqw