大厂架构:每天数百亿用户行为数据,美团怎么实现秒级转化分析?

导读
用户行为分析是数据分析中非常重要的一项内容,在统计活跃用户,分析留存和转化率,改进产品体验、推动用户增长等领域有重要作用 。美团点评每天收集的用户行为日志达到数百亿条,如何在海量数据集上实现对用户行为的快速灵活分析,成为一个巨大的挑战 。为此,我们提出并实现了一套面向海量数据的用户行为分析解决方案,将单次分析的耗时从小时级降低到秒级,极大的改善了分析体验,提升了分析人员的工作效率 。
本文以有序漏斗的需求为例,详细介绍了问题分析和思路设计,以及工程实现和优化的全过程 。
问题分析
下图描述了转化率分析中一个常见场景,对访问路径“首页-搜索-菜品-下单-支付”做分析,统计按照顺序访问每层节点的用户数,得到访问过程的转化率 。
统计上有一些维度约束,比如日期,时间窗口(整个访问过程在规定时间内完成,否则统计无效),城市或操作系统等,因此这也是一个典型的OLAP分析需求 。此外,每个访问节点可能还有埋点属性,比如搜索页上的关键词属性,支付页的价格属性等 。从结果上看,用户数是逐层收敛的,在可视化上构成了一个漏斗的形状,因此这一类需求又称之为“有序漏斗” 。

大厂架构:每天数百亿用户行为数据,美团怎么实现秒级转化分析?

文章插图
 
这类分析通常是基于用户行为的日志表上进行的,其中每行数据记录了某个用户的一次事件的相关信息,包括发生时间、用户ID、事件类型以及相关属性和维度信息等 。现在业界流行的通常有两种解决思路 。
  1. 基于Join的SQL
select count (distinct t1.id1), count (distinct t2.id2), count (distinct t3.id3)from (select uuid id1, timestamp ts1 from data where timestamp >= 1510329600 and timestamp < 1510416000 and page = '首页') t1left join(select uuid id2, timestamp ts2 from data where timestamp >= 1510329600 and timestamp < 1510416000 and page = '搜索' and keyword = '中餐') t2on t1.id1 = t2.id2 and t1.ts1 < t2.ts2 and t2.ts2 - t1.ts1 < 3600left join(select uuid id3, timestamp ts3 from data where timestamp >= 1510329600 and timestamp < 1510416000 and page = '菜品') t3on t1.id1 = t3.id3 and t2.ts2 < t3.ts3 and t1.ts1 < t3.ts3 and t3.ts3 - t1.ts1 < 3600
  1. 基于UDAF(User Defined Aggregate Function)的SQL
selectfunnel(timestamp, 3600, '首页') stage0,funnel(timestamp, 3600, '首页', '搜索', keyword = '中餐') stage1, funnel(timestamp, 3600, '首页', '搜索', '菜品') stage2from datawhere timestamp >= 1510329600 and timestamp < 1510416000 group by uuid对于第一种解法,最大的问题是需要做大量join操作,而且关联条件除了ID的等值连接之外,还有时间戳的非等值连接 。当数据规模不大时,这种用法没有什么问题 。但随着数据规模越来越大,在几百亿的数据集上做join操作的代价非常高,甚至已经不可行 。
第二种解法有了改进,通过聚合的方式避免了join操作,改为对聚合后的数据通过UDAF做数据匹配 。这种解法的问题是没有足够的筛选手段,这意味着几亿用户对应的几亿条数据都需要遍历筛选,在性能上也难以接受 。
那么这个问题的难点在哪里?为什么上述两个解法在实际应用中变得越来越不可行?主要问题有这么几点 。
  1. 事件匹配有序列关系 。如果没有序列关系就非常容易,通过集合的交集并集运算即可 。
  2. 时间窗口约束 。这意味着事件匹配的时候还有最大长度的约束,所以匹配算法的复杂度会进一步提升 。
  3. 属性和维度的需求 。埋点SDK提供给各个业务线,每个页面具体埋什么内容,完全由业务决定,而且取值是完全开放的,因此目前属性基数已经达到了百万量级 。同时还有几十个维度用于筛选,有些维度的基数也很高 。
  4. 数据规模 。目前每天收集到的用户行为日志有几百亿条,对资源和效率都是很大的挑战 。
基于上述难点和实际需求的分析,可以总结出几个实际困难,称之为“坏消息” 。
  1. 漏斗定义完全随机 。不同分析需求对应的漏斗定义完全不同,包括具体包含哪些事件,这些事件的顺序等,这意味着完全的预计算是不可能的 。
  2. 附加OLAP需求 。除了路径匹配之外,还需要满足属性和维度上一些OLAP的上卷下钻的需求 。
  3. 规模和性能的矛盾 。一方面有几百亿条数据的超大规模,另一方面又追求秒级响应的交互式分析效率,这是一个非常激烈的矛盾冲突 。


    推荐阅读