游戏中的abtest功能实现,演进与复盘
前⾔
abtest是⼀种很常见的,利⽤真实⽤户来测试的⽅法。在游戏中,可以⽤abtest来测试不同的活动,不同的商品,不同的定价,不同的匹配策略等等的⽤户接受程度。
初版:简单的ab池划分与细分
在接到第⼀版需求到时候,需求相当简单,策划/运营想要⼀个可以做abtest的⼯具,⽀持细分和多概率组。
基于这个需求,第⼀版本的abtest需要做三件事情,将玩家的属性统计出来;将玩家按不同的属性进⾏划分,进⽽按照不同的概率进⾏分池;不同业务可以配置在同⼀个abtest组⾥⾯,⽐如说玩家看到的公告需要和⾃⼰看到的商品协同。
在这⼀阶段:最终实现的abtest⽅案如下:
1. 配置表设计
由于需要将不同的业务可以配置到同⼀个组⾥⾯,abtest的配置表被设计成了三张表分离:分别是业务表,abtest表和细分表。这是出于⼀下考虑:
a. abtest需要有做到不同业务可以协同测试。所以abtest表独⽴出来,对开发来说更加直观。
b. abtest中有组的概念。⽽同⼀组中,对应的细分条件是⼀致的,也就是说,abtest中,相同的组会共⽤同⼀个细分条件,同时,不
同的组,也有可能共⽤同⼀个细分条件。那么将细分纬度再抽离出⼀个表,是符合程序逻辑的。
c. 在流程设计中,登陆的时候需要根据abtest的细分条件来⽣成玩家的标签,因此将细分条件抽出来成表,⽅便程序实现。
2. 游戏测按照策划的需求,在不同的模块统计⽤户的⾏为。在玩家登出的时候进⾏汇总,形成玩家的属性。
由于游戏中,玩家的不同属性是分表存储,不同⾏为会到不同的模块进⾏处理。如果每次⾏为都汇总到某⼀个特定的表或者模块中,则会将这个表/模块变成热点。举个例⼦,在游戏中,活动模块会接收玩家的各个事件,⽐如说登陆,对局结算记录,购买,获得,使⽤物品等事件。那么该模块在整个游戏周边系统就会就会成为⼀个热点,所有的玩家⾏为都有可能对该模块发送请求。为了避免abtest也
出现这样的情况(毕竟abtest在游戏中不应该成为⼀个⾼性能开销的事情),所以采取的⽅案就是在不同的模块分开统计⽤户的⾏为,降低内⽹的请求量;在登出的时候做统⼀处理。
3. 在玩家登陆的时候,依照配置表和玩家的属性,⽣成玩家的标签,作为玩家的基础属性,附带在玩家的请求包中。
在初版的设计中,考虑的最多的就是降低abtest对现有业务的影响,⽐如说拉取db所造成的影响。如果是在玩家拉取具体业务的时候进⾏判断,则需要额外拉取db表,对业务来说会增加时延,同时对业务的改造会⽐较⼤。所以考虑的就是将abtest细分条件转为玩家的标签。各个业务只需要判断⼀下玩家的标签即可。
4. 在玩家获取商店,活动,公告等配置的时候,根据玩家标签和概率,来判断玩家是否命中测试。魔方教程公式口诀七步
在玩家拉取具体业务的配置时,会取根据玩家的标签,来判断玩家是否命中该业务。对业务的改动相当的⼩。当玩家命中标签后,会继续根据玩家的uin尾号来判断玩家的概率。
这个⽅案在开发完后,碰到的最⼤问题是配置表对策划来说⾮常难理解。策划如果需要配置⼀个abtest活动,需要同时配置三张表。当时策划的原话是:我配了⼤半辈⼦表,第⼀次见到这么复杂的表,你⽜逼。
这也导致了另⼀个问题,这个需求的测试⾮常难测,因为测试,策划配表的门槛变得⾮常的⾼。 在后续的测试中,发现了很多初版⼀直遗留下来的bug。
配置拆分:
抖音聊天在初版完成后不久,游戏的海外版就对配置表有了新的要求-要求abtest能够⽀持运营⼯具配置。这⾥介绍⼀下背景。
我们游戏有两种配置⽅式,⼀种是⾛本地对配置表进⾏配置,另外⼀种是⾛运营⼯具进⾏配置下发,配置表是落db的。游戏中对于运营⼯具配置的⽀持⾮常少,在需求提出的时候,只有公告和活动⽀持运营⼯具下发,⽽且实现⽅式及其复杂。作为游戏的开发,我们对于运营⼯具来下发配置的稳定性深表怀疑。⽽事实上,在预⽣产环境,也的确出现过由于该⼯具导致的奇奇怪怪的问题。
abtest实现中,对于游戏的打标签是在登录这⼀关键路径中进⾏的,登录相关的模块对稳定性要求很⾼,如果在该模块⽀持运营⼯具,会带来很可怕的风险。
此外,在配置表设计中,业务和abtest之间的配置表是有交叉,⽽且相互影响的。⽐如说细分表,是各个业务模块共⽤的。如果说abtest需要⽀持运营⼯具,那么就存在着,⽀持运营⼯具的abtest细分表,需要从运营⼯具下发;⽽不⽀持运营⼯具的细分表,则需要从配置表中获得。那么,⼀张细分表则会有多个来源,会导致业务逻辑的混乱。
基于上述背景,就需要考虑abtest的配置表修改和拆分了。最终决定修改abtest的配置表和业务流程。
在这⼀阶段,改进的abtest⽅案如下:
原有的abtest表和细分表废弃。abtest的配置项,放在各个的业务表中。
2. 玩家标签和命中测试
玩家不再有标签的概念,登录流程中,不再给玩家打标签。判断玩家是否命中放在玩家拉去具体业务时进⾏。玩家在拉配置时,各个业务需要取拉取玩家的细分纬度,⾃⼰进⾏判断。
拆分带来的好处很明显:
1. 业务之间的配置表不会有交集。策划配置表不需要跨表了。
2. abtest的配置不会影响到关键流程,降低了运营⼯具对游戏后台的风险。
但是拆分也有很多副作⽤:
1. abtest带来的性能开销增⼤了。拆分到各个业务后,各个业务需要⾃⼰取拉取玩家的细分统计,⾃⼰取判断玩家的属性。
2. abtest更加的侵⼊具体的业务代码,⼲扰业务流程了。
理工科热门专业尽管拆分到来的副作⽤很⼤,可以说是在游戏的整个业务逻辑中硬⽣⽣插⼊了⼀层。但是考虑到这么做,能够在最快时间内,避免运营⼯具冲击到游戏的登录主流程,所带来的时延和性能开销相对来说还是可以接受的。毕竟对于业务来说,只要进程还在,逻辑还能正常跑,就能够正常提供服务。活着才有dps,挂了就是重⼤运营事故。
在这⼀阶段,最终实现的abtest⽅案如下:
1. 配置表设计
配置放在各个业务⾃⼰的配置表中,原有的两张单独的表废除。
各个业务的配置表中,增加abtest选项和细分选项。要求策划配表的时候,同⼀组的abtest,细分条件需要配置成⼀样的。
2. 游戏测按照策划的需求,在不同的模块统计⽤户的⾏为。在玩家登出的时候进⾏汇总,形成玩家的属性。
古朗月行全诗解释3. 在玩家获取商店,活动,公告等配置的时候,拉取玩家的统计数据,根据玩家的统计数据和配置的概率,来判断玩家是否命中测试。
在玩家拉取具体业务的配置时,同时取拉取玩家的统计数据,通过统计数据实时计算玩家是否命中abtest的细分条件。再依据玩家的uin尾号来判断玩家的概率区间。
批量重命名这个⽅案在很⼤程度上,导致了abtest 原来对尽量避免对业务造成影响的设计思路 被破坏。 在初版中,abtest在业务层⾯,在代码层⾯上,仅仅是多加了⼀个if语句的关系。⽽现在则演变成了侵⼊业务逻辑,额外增加了很多代码改动。从这⼀点来看,初版的这⼀思路算是完全的失败了。当然这不是思路本⾝的问题,只是随着需求的变更,原有的设计不能再满⾜要求了,那么设计就需要随着需求变更。
尽管abtest⼊侵了原有的业务,并带来了⼤量的业务改动。但是这⼀改动在满⾜需求的同时,减少abtest配置对主流程的影响,从这⼀点来看,还算是⾮常有意义的。事实上,随着后续需求的进⼀步提出,以及abtest逐步向精细化运营靠拢,这⼀改动⽀撑了部分精细化需求的改动。
从abtest到精细化运营
事实上,不管是abtest,还是精细化运营,游戏的公共研发体系都是有⾮常成熟的⽅案的。但是这只是针对国内的游戏⽽⾔的。尽管⽬前公司的新游戏都在想着出海,但是公共研发体系的步伐还是会慢⼀点。毕竟相对国内公司这么多游戏,出海的游戏还是少的。 但是随着⼯作室的游戏在海外上线,精细化运营也变成了不得不做的事情。这个时候,如果公司的组件⽆法提供⽀持,游戏⾃⼰就需要开发
精细化运营的功能。⽽abtest在之前版本的迭代中,具备了部分精细化运营的基础,将之升级为精细化运营也是成本最优的选项。
运营在这⼀版本的需求中,增加了很多细分条件。同时对abtest的功能提了很多新的需求。⽐如说要求abtest能够⽀持更长的时间纬度的统计;玩家命中abtest后需要持续可见,⽽不会随着⾃⼰条件的变化,导致相应的测试项变得不可见;玩家命中abtest后,需要能够⽀持命中失效的时间。⽐如说命中七天后就不可见等。
在前两个版本的abtest中,有⼀个问题是玩家命中条件这件事情是⽆状态的。举⼀个栗⼦,如果⼀个abtest的细分条件是5-10级玩家可见。那么当玩家10级时,他可以看到测试项,但是当他升级到11级后,那么他就看不到了。
这个在abtest中对测试会造成影响,但是相对来说是可以容忍的。因为abtest是短期的事情,但是随着abtest逐步过渡为精细化运营。就需要对玩家命中的时间点进⾏记录。
由于上⼀个版本中,abtest已经极⼤的⼊侵了各个业务模块,在这个版本的需求中,对业务模块对修改就毫⽆⼼理负担了。因此这个版本的改进⽅案就⽐较简单:
1. 在各个业务模块⾃⼰对db中,存储这个玩家命中了abtest的记录,包括命中时间和id等。
2. 基于玩家命中的记录,判断是否需要对玩家展⽰对应的配置项。
在这⼀阶段,最终实现的abtest⽅案如下:怎么设置拍一拍
配置放在各个业务⾃⼰的配置表中,原有的两张单独的表废除。
各个业务的配置表中,增加abtest选项和细分选项。要求策划配表的时候,同⼀组的abtest,细分条件需要配置成⼀样的。
2. 游戏测按照策划的需求,在不同的模块统计⽤户的⾏为。在玩家登出的时候进⾏汇总,形成玩家的属性。
3. 在玩家获取商店,活动,公告等配置的时候,拉取玩家的统计数据,根据玩家的统计数据和配置的概率,来判断玩家是否命中测试。
在玩家拉取具体业务的配置时,同时取拉取玩家的统计数据和命中记录,通过统计数据和命中记录判断玩家能够看到这个配置项。
这个⽅案尽管思路上⾮常简单,但是完全破坏了abtest不影响业务的设计思路。abtest 现在需要业务拉去玩家的统计数据,⽽且要求业务记录下玩家的命中记录,这就相当于abtest已经完全成为了业务的⼀部分了。
⽽且事实上,在完成这⼀⽅案的时候,发现abtest在业务模块的代码已经越来越多,从⼀开始的⼀个if语句,到第⼆版⼀个函数。再到现在,需要有五六个函数,两个额外的db读写,需要嵌⼊到业务模块中。尽管从需求的重要程度来说,这么做是值得的。但是作为开发⽽⾔,新增⼀个需求,需要写五六个类似的代码,并不优雅,⽽且增加了犯错的机会。
abtest架构重构
随着运营的需求不断变更和abtest需要⽀持的模块的增多,原有的abtest架构已经逐渐成为了⼀个负担。每当需求变更,就需要对多个模块进⾏同步的更改;每当需要⽀持新的模块,就需要侵⼊新的业务模块。这不⾜以⽀撑起游戏业务对快速迭代和稳定性的⾼要求。因此就需要对abtest进⾏重构。
重构对⽬的有两个:
1. 降低abtest对业务模块的侵⼊性。这个侵⼊性体现在三个⽅⾯。⼀个业务⽀持abtest所需要的改动尽量降低;abtest的存储和判断逻
辑聚合到单⼀的模块,不再嵌⼊到别的模块;abtest的统计不要再嵌⼊到账号模块中。
2. 将abtest的处理逻辑前置,降低对业务处理性能的影响。
这个阶段的⽅案如下:
3. 配置表设计
配置放在各个业务⾃⼰的配置表中,原有的两张单独的表废除。
各个业务的配置表中,增加abtest选项和细分选项。要求策划配表的时候,同⼀组的abtest,细分条件需要配置成⼀样的。
4. 游戏测按照策划的需求,在不同的模块统计⽤户的⾏为。在玩家登出的时候进⾏汇总,形成玩家的属性。
5. 游戏中新增abtset模块。在玩家登录时,在该模块先判断玩家是否命中各个业务的配置,并将结果写⼊db。在玩家登出的时候,将玩
家数据进⾏汇总。
6. 在玩家获取商店,活动,公告等配置的时候,拉取玩家的命中结果表即可。
这个⽅案,将原有的abtest中,⼊侵到业务模块的代码给⼤量抽离出来了。仅保留下拉取数据库和新增数据的逻辑。
这么做,可是使abtest对业务的侵⼊降到最低。这样可以将abtest对业务的稳定性的影响降到最低,同时将abtest的逻辑聚合到⼀个模块,也可以使abtest的迭代更加灵活。
同时,将abtest的统计结果和命中记录拆分成两个表格,这样可以降低对db的压⼒。
遇到的问题
1. 玩家流量分层的问题:
abtest的玩家分层是⼀个很常见的问题。在刚开始设计的时候,考虑过这个问题,但是并没有认真的去做考虑。
在刚开始的版本,使⽤⼀个偏移值来做流量的分层,按玩家uin的尾号作为命中与否的依据。但是这带来⼀个问题,不同的测试,尽管采⽤了不同的偏移值,但是由于⽤户区间是连续的,各个测试之间依然会相互影响。
因此,在后⾯的版本中,引⼊了层级的概念。层级是⼀个整数,程序会根据这个整数,会将玩家uin不同位数的数字取出来拼成玩家的层级tag。 ⽐如层级1234, 就会将玩家uin第⼀位数字取出来做千位,将玩家第⼆位数字取出来做百位,以此类推。
这样做的好处有两个:算法简单,⽅便出现问题时定位问题。
2. 玩家命中记录和玩家命中记录持久化的问题:
abtest是否需要记录玩家曾经命中与否是⼀个之前没有考虑过的问题。abtest在⼀些短期内测试或者⼀些所见即所得的场景时,并不会需要考虑这样的问题。但是在⾯对⼀些时间周期较长的场景下,⽐如说⼀些持续周期较长的活动,特别是在精细化场景下,玩家命中与否的条件可能随时会变更,这个时候将玩家命中记录就显得很重要了。
不过在实际运⽤中,还是有⼀些⼩问题。⽐如说,运营在使⽤过程中,希望玩家在购买完通⾏证前,给他推送公告,但是购买完成后就不需要再推送了。这个需求就和上⾯的需求产⽣⽭盾了。因为它希望随着玩家⾏为的变更,玩家的命中记录也要随之变更。只能说,在开发完⼀个⼯具后,⽤户就会想出⽆限种⽤它的途径,这个时候出现了功能不符合预期也是正常的。
3. 效果验证:
从程序的⾓度来讲,最需要被验证的就是abtest是否真的是abtest,玩家的概率是否真的如配置所想要的那样被随机。这个时候,程序就需要将命中记录上报出去,通过宏观的数据来验证命中和随机效果。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论