37DATA

浅谈留存方案的演变

最近正在进行CK下架相关的工作,任务拆解后发现耗时较多有不少是和留存相关的。
日常工作中,业务及产品同事提及,留存的数据需要重跑或者加维度,开发同事就会有些头大,鉴于以上,大致聊下“留存方案”的演变。

一、留存的概念

Image

1.1 在咱们常用的数据分析后台,涉及留存的指标,会有俩种:xx日留存数、xx日留存率
1.2 差别在于 xx日留存率 = xx日留存数 / 对应新增(注册或安装等),不同的业务线,规则或许有差。
1.3 以海外1日留存数为例,简单的概念就是:X日产生注册的用户,在X+1日有过登录行为则算。
1.31 例如:9.1日A用户注册,9.2日A用户登录,9.3日没登,9.4日登录,那么A用户的1日留存+1,2日留存+0,3日留存+1 。
1.4 为什么概念还要分成简单,复杂,是因为在真实的业务场景中,留存是基于注册这个前提来产生的,而注册会带有规则,并非一个用户在一个平台只有一次注册。
1.41 也正是因为如此,导致一个用户在注册、登录、充值等行为时,需赋予了很多(几十个)基础属性
1.42 换言之,真实的业务后台,用户的留存是基于用户满足特定条件下的登录,才能算作留存。

简单总结下:用户留存和注册(安装)、登录行为挂钩;一个帐号并非在一个平台只能注册一次。

二、方案的演变:

前提:现有用户的核心行为数据,第一手数据(增删改)还是落盘到MySQL的,留存也是这样。
2.1 v1版本: 利用SQL直接查询登录表
2.11 早期数据量少,登录表总日志不超千万
2.12 需保证登录表有用户(注册时间及相关属性)字段

Image

2.2 v2版本:建立中间表存储
2.21 随着数据量的增加,单日登录条目高峰已到百万级别,整表已达上亿级别,时频:每天或每半天一跑
2.22 于是决定使用中间表,进行存储,程序的核心逻辑如下:
2.23 表结构设计大致如下:
2.231 REG_SUM(注册数)、DAY_1(1日留存)

Image

2.23 程序的大致逻辑:

Image

2.3 v3版本:增加了许多新的维度 + where条件后面的多个字段加密成唯一串进行存储 

2.31 随着数据量的增加,单日登录条目已到千万级别,时频:每小时一跑
2.32 登录数据不断的增加,业务不断的变化导致经常需要增加维度,程序的时频变得更高
2.33 之前的版本,程序在执行时,花在更新留存,也就是update set day_x=xx 的这个环节特别耗时
2.34 耗时的主要原因是,以分地区留存为例:
2.341 登录表总条目数(60亿)单日写入(1200W),分地区留存表总条目数(4亿)单日写入(40W)。
2.342 随着业务增,表的维度不断增加(已有30个维度),整个表的字段已达102个
2.343 维度的增加导致写入留存表的数量不断上升,加之 update 后面的where 条件太长,导致索引低效,更新一天登录的留存需耗时几十分钟甚至更长
2.35 鉴于此,于是将where后面的字段连接后加密成唯一串,更新一天的留存耗时从几十分钟变为几分钟 

Image

三、时间去哪了


上文大致讲述了留存方案的步骤和演变过程,最后在聊下为什么CK下架,留存任务耗时较多
3.1 不仅仅是为了兼容Holo的SQL语法,想趁此进行重构
3.11 原有的程序,因为不断的迭代,代码的阅读门槛较高
3.12 存在多套脚本,缺少统一方法,维度唯一串引入后, 维护成本较高

3.2 留存指标是一个核心指标 + 不止一种留存方式
3.21 数据后台有的菜单,80%以上的菜单,都会和留存有相关性
3.22 涉及到留存相关的中间表,有四五张表,例如:分游戏留存、分地区留存、分账号留存等。

3.3 维度唯一串的引入,虽然提高了更新的效率,也加大了更新的复杂度
3.31 表名一直是同一个,但随着业务的发展维度的增加,更新的条件虽然还是唯一串,但加密会产生变化
3.32 想要重构和优化,必须得理清楚,现有唯一串,从历史到现在的数据,对应的加密规则是怎样:
3.33 举例说明:

Image

3.4 因为涉及重构和优化,在程序效率,扩展性以及数据核实上也会花费一定时间。

备注:优化及重构的方案,等完整落地后,我再做下补充。

感谢您的阅读。