当前位置:首页 > 问答 > 正文

从用户行为出发聊聊漏斗算法优化和Redis性能提升那些事儿

前段时间,我们团队集中处理了一个挺有意思的问题,就是关于用户在我们App上完成某个关键任务的流程优化,这个任务简单说,就是用户从看到某个商品,到最终成功下单支付的整个过程,我们发现,中间流失的用户比预想的要多,就像一个大漏斗,入口进来的人很多,但一层层漏下去,最后没剩多少了,这就是我们常说的“用户行为漏斗”出了问题。

最开始,我们用来分析这个漏斗的数据,是靠一套传统的统计方法,来源:团队内部技术文档),就是用户在App里每完成一步,点击商品”、“加入购物车”、“点击支付”,都会向我们的服务器发送一个记录,然后我们通过查询数据库,统计出每一步的人数,再算出每一步到下一步的转化率,这个方法听起来挺直接的,但实际用起来问题一大堆。

从用户行为出发聊聊漏斗算法优化和Redis性能提升那些事儿

最头疼的就是慢,当用户量一大,特别是搞促销活动的时候,每秒都有成千上万的记录涌进来,数据库每次都要去统计这些海量的数据,就像让你在一个人山人海的广场上,实时数清楚有多少人走进了A商店,又有多少人从A商店走进了B商店,根本数不过来,速度奇慢,等我们拿到数据报告,经常都是几个小时以后的事情了,看到的都是“历史”,根本没法实时知道现在漏斗的状况,我们刚上线一个优化,想马上看看效果,结果等报告等得黄花菜都凉了,决策效率非常低。

这种统计方式还不灵活,我们产品经理如果想换个角度看问题,比如不想看全天的数据,只想看最近半小时内从上海地区来的用户的漏斗情况,这种临时的、细分的查询对数据库的压力就更大了,几乎没法快速响应。

从用户行为出发聊聊漏斗算法优化和Redis性能提升那些事儿

我们决定对这套漏斗分析系统动个手术,核心思路就是用Redis来改造它,Redis是一种速度特别快的内存数据库,数据主要放在服务器的内存里,读写速度比存在硬盘上的传统数据库快好几个数量级,特别适合做这种需要实时计算的场景。

那具体怎么用Redis来刻画用户行为漏斗呢?(来源:团队技术分享会记录)我们借鉴了一个叫做“HyperLogLog”的Redis数据结构,这个东西很神奇,它不能记录每个用户的详细行为,但它可以用极小的空间,非常精确地估算出某个集合里有多少个不重复的用户,有一万个用户浏览了商品,HyperLogLog只需要占用大概十几KB的内存,就能估算出总数,而且误差率还很低。

从用户行为出发聊聊漏斗算法优化和Redis性能提升那些事儿

这样一来,我们的漏斗计算就完全变了样,我们还是让用户每完成一步就发送记录,但这次不再是写入慢吞吞的数据库,而是立刻去操作Redis,一个用户ID为123的用户点击了商品,我们就在Redis里为一个叫“步骤1:点击商品”的HyperLogLog结构中,添加这个用户ID,同样,当他加入购物车时,我们再向“步骤2:加入购物车”的HyperLogLog添加同一个用户ID。

因为所有操作都在内存里完成,所以速度飞快,每秒处理几十万次记录毫无压力,当我们需要看实时漏斗时,只需要对Redis下一个简单的命令,让它分别计算出“步骤1”有多少人、“步骤2”有多少人……瞬间就能得到每一步的用户数估算值,然后立刻算出转化率,我们终于可以实时地盯着漏斗的变化了,哪个步骤突然卡住了,能马上发现。

除了用HyperLogLog,我们还用了Redis的“位图”结构(来源:同一技术分享会),来应对更精细的查询,比如产品经理想分析“完成支付的用户中,有多少人也领取了优惠券”,我们可以把领取了优惠券的用户ID集合记录在一个位图里,把完成了支付的用户ID记录在另一个位图里,位图可以非常高效地进行“与”、“或”这样的逻辑运算,一瞬间就能算出同时满足两个条件的用户数量,满足了灵活分析的需求。

通过这次优化,我们收获很大,最大的感受就是,技术选型一定要贴合实际的业务场景,以前我们总想着用最“重”、功能最全的数据库来解决所有问题,结果反而被拖累,而Redis这种看似简单的工具,用对了地方,就能四两拨千斤,我们的漏斗分析变得又快又灵活,产品团队可以大胆地尝试各种优化方案,并能立刻看到数据反馈,整个迭代速度都提上来了,因为Redis性能极高,服务器压力也小了很多,更加稳定,这件事让我们明白,从用户行为的真实需求出发,选择最合适的技术,往往比追求技术的复杂度更能解决问题。