什么是 ABTest
产品的改变不是由我们随便「拍脑袋」得出,而是需要由实际的数据驱动,让用户的反馈来指导我们如何更好地改善服务。正如马蜂窝 CEO 陈罡在接受专访时所说:「有些东西是需要 Sense,但大部分东西是可以用 Science 来做判断的。」
说到 ABTest 相信很多读者都不陌生。简单来说,ABTest 就是将用户分成不同的组,,同时在线试验产品的不同版本,通过用户反馈的真实数据来找出采用哪一个版本方案更好的过程。
我们将原始版本作为对照组,以每个版本进行尽量是小的流量迭代作为原则去使用 ABTest。一旦指标分析完成,用户反馈数据表现***的版本再去全量上线。
很多时候,一个按钮、一张图片或者一句文案的调整,可能都会带来非常明显的增长。这里分享一个ABTest 在马蜂窝的应用案例:
如图所示,之前我们搜索团队和电商团队希望优化一个关于「滑雪」的搜索列表。可以看到优化之前的页面显示从感觉上是比较单薄的。但是大家又不确定复杂一些的展现形式会不会让用户觉得不够简洁,产生反感。因此,我们将改版前后的页面放在线上进行了 ABTest。最终的数据反馈表明,优化之后的样式 UV 提高了 15.21%,转化率提高了 11.83%。使用 ABTest 帮助我们降低了迭代的风险。
通过这个例子,我们可以更加直观地理解 ABTest 的几个特性:
为了让我们的验证结论更加准确、合理并且高效,我们参照 Google 的做法实现了一套算法保障机制,来严格实现流量的科学分配。
基于 Openresty 的多层分流模型
大部分公司的 ABTest 都是通过提供接口,由业务方获取用户数据然后调用接口的方式进行,这样会将原有的流量放大一倍,并且对业务侵入比较明显,支持场景较为单一,导致多业务方需求需要开发出很多分流系统,针对不同的场景也难以复用。
为了解决以上问题,我们的分流系统选择基于 Openresty 实现,通过 HTTP 或者 GRPC 协议来传递分流信息。这样一来,分流系统就工作在业务的上游,并且由于 Openresty 自带流量分发的特性不会产生二次流量。对于业务方而言,只需要提供差异化的服务即可,不会侵入到业务当中。
选型 Openresty 来做 ABTest 的原因主要有以下几个:
整体流程
在设计 ABTest 系统的时候我们拆分出来分流三要素,***是确定的终端,终端上包含了设备和用户信息;第二是确定的 URI ;第三是与之匹配的分配策略,也就是流量如何分配。
首先设备发起请求,AB 网关从请求中提取设备 ID 、URI 等信息,这时终端信息和 URI 信息已经确定了。然后通过 URI 信息遍历匹配到对应的策略,请求经过分流算法找到当前匹配的 AB 实验和版本后,AB 网关会通过两种方式来通知下游。针对运行在物理 web 机的应用会在 header 中添加一个名为 abtest 的 key,里面包含***的 AB 实验和版本信息。针对微服务应用,会将***微服务的信息添加到 Cookie 中交由微服务网关去处理。
稳定分流保障:MurmurHash算法
分流算法我们采用的 MurmurHash 算法,参与算法的 Hash 因子有设备 id、策略 id、流量层 id。
MurmurHash 是业内 ABTest 常用的一个算法,它可以应用到很多开源项目上,比如说 Redis、Memcached、Cassandra、HBase 等。MurmurHash 有两个明显的特点:
下面简单解释下正交和互斥:
流量层内实验分流
流量层内实验的 hash 因子有设备 id、流量层 id。当请求流经一个流量层时,只会***层内一个实验,即同一个用户同一个请求每层最多只会***一个实验。首先对 hash 因子进行 hash 操作,采用 murmurhash2 算法,可以保证 hash 因子微小变化但是结果的值变化激烈,然后对 100 求余之后+1,最终得到 1 到 100 之间的数值。
示意图如下:
实验内版本分流
实验的 hash 因子有设备 id、策略 id、流量层 id。采用相同的策略进行版本匹配。匹配规则如下:
稳定性保障:多级缓存策略
刚才说到,每一个请求来临之后,系统都会尝试去获取与之匹配的实验策略。实验策略是在从后台配置的,我们通过消息队列的形式,将经过配置之后的策略,同步到我们的策略池当中。
我们最初的方案是每一个请求来临之后,都会从 Redis 当中去读取数据,这样的话对 Redis 的稳定性要求较高,大量的请求也会对 Redis 造成比较高的压力。因此,我们引入了多级缓存机制来组成策略池。策略池总共分为三层:
***层 lrucache,是一个简单高效的缓存策略。它的特点是伴随着 Nginx worker 进程的生命周期存在,worker 独占,十分高效。由于独占的特性,每一份缓存都会在每个 worker 进程中存在,所以它会占用较多的内存。
第二层 lua_shared_dict,顾名思义,这个缓存可以跨 worker 共享。当 Nginx reload 时它的数据也会不丢失,只有当 restart 的时候才会丢失。但有个特点,为了安全读写,实现了读写锁。所以再某些极端情况下可能会存在性能问题。
第三层 Redis。
从整套策略上来看,虽然采用了多级缓存,但仍然存在着一定的风险,就是当 L1、L2 缓存都失效的时候(比如 Nginx restart),可能会面临因为流量太大让 Redis 「裸奔」的风险,这里我们用到 lua-resty-lock 来解决这个问题,在缓存失效时只有拿到锁的这部分请求才可以进行回源,保证了 Redis 的压力不会那么大。
我们在缓存 30s 的情况下对线上数据的进行统计显示,***级缓存***率在 99% 以上,第二级缓存***率在 0.5 %,回源到 Redis 的请求只有 0.03 %。
关键特性
性能表现
响应时间分布
TPS 分布
测试工具采用 JMeter,并发数 100,持续 300s。
从响应时间来看,除了刚开始的时候请求偏离值比较大,之后平均起来都在 1ms 以内。分析刚开始的时候差距比较大的原因在于当时的多级缓存里面没有数据。
TPS的压测表现有一些轻微的下降,因为毕竟存在 hash 算法,但总体来说在可以接受的范围内。
A/B发布
常规 A/B 发布主要由 API 网关来做,当面临的业务需求比较复杂时, A/B 发布会通过与与微服务交互的方式,来开放更复杂维度的 A/B 发布能力。
小结
需要注意的是,ABTest 并不完全适用于所有的产品,因为 ABTest 的结果需要大量数据支撑,日流量越大的网站得出结果越准确。通常来说,我们建议在进行 A/B 测试时,能够保证每个版本的日流量在 1000 个 UV 以上,否则试验周期将会很长,或很难获得准确(结果收敛)的数据结果推论。
要设计好一套完整的 ABTest 平台,需要进行很多细致的工作,由于篇幅所限,本文只围绕分流算法进行了重点分享。总结看来,马蜂窝 ABTest 分流系统重点在以下几个方面取得了一些效果:
近期规划改善:
这套系统未来需要改进的地方还有很多,我们也将持续探索,期待和大家一起交流。
本文作者:李培,马蜂窝基础平台信息化研发技术专家;张立虎,马蜂窝酒店研发静态数据团队工程师。
【本文是专栏作者马蜂窝技术的原创文章,作者微信公众号马蜂窝技术(ID:mfwtech)】
戳这里,看该作者更多好文
文章题目:马蜂窝ABTest多层分流系统的设计与实现
文章转载:http://www.csdahua.cn/qtweb/news45/411295.html
网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网