埋点简介
埋点是用来分析用户使用应用行为过程的最常用的数据采集方案,埋点数据的特征是大数据和连贯性。
大数据表现为埋点信息量大和埋点数量多。埋点信息量大是指单个埋点就包含了用户(Who)、时间(When)、位置(Where)、行为(How)、设备、应用及事件(What)等信息。埋点数量多是指不同的埋点会分为不同的事件类型比如应用的启动、页面的浏览、按钮的点击、内容的展现等,单个用户一次使用应用的期间就可能触发几十上百个埋点事件,千万日活的应用每天埋点上报总量就至少是百亿以上的量级。
连贯性表现为对行为过程的描述是连贯的,以单个设备产生的埋点 id 按照埋点客户端时间戳排序,能够清晰的看数该设备的一系列行为,以电商类的应用为例,连贯性的行为可能是应用启动、商品列表展示、点击搜索、搜索结果展示、某个商品卡片展示、点击商品卡片、商品详情展示、加入购物车按钮点击等等。通过这样的连贯的行为就可以分析【加入购物车】这个动作发生的原因可能是【搜索】到了感兴趣的商品。正是基于埋点的连贯性为应用的行为分析、归因分析等提供了依据。
埋点质量
埋点的质量简单讲就是看埋点数据是否准确,基于前边提到的埋点数据特征,将埋点质量或者准确性也分为两个方面,一是埋点采集上报的数量是否准确,二是埋点上报的信息是否准确。本篇文章是站在前端角度,主要讲第一个方面采集上报方面的质量问题,第二个方面只做简要描述。
要衡量埋点的质量,就需要一个可量化的指标,对于埋点采集上报数量业界常用的指标是埋点丢失率。
埋点丢失率
埋点丢失率是指从埋点采集到上报再到最终落库后埋点丢失数量的比率,计算公式非常简单简单:埋点丢失的数量 ➗ 埋点应上报的总数。用下图为例,简单演示丢失率的计算就是丢失的条数 2 / 总数 15,得出丢失率为 13.3%。
丢失率统计方案
丢失率的计算公式比较简单,问题是如何统计丢失的数量。造成埋点丢失的原因也比较多,比如前端进程杀死或崩溃时埋点采集了但没上报,网络问题埋点发送不出去或者发送过程中丢失等等,这些单靠服务端是无法进行完全统计的,因此方案依赖前端的实现。
但以我们 Web 前端为例,每个浏览器设备是独立的,需要以单个设备为维度进行埋点丢失的统计。于是丢失率的计算方式升级为以下方式:
计算逻辑比较清楚了,接下来是其中的 device_id 和埋点丢失的数量的统计,这就需要在埋点上报时携带设备唯一标识(device_id)和用于标记是第几条埋点的自增 id。
其中设备 id 比较容易理解,首次可以随机生成一个 uuid 存储到浏览器的本地存储中,如果考虑到有多个顶级域名相同的子产品,比如 https://www.kuaishou.com 和 https://live.kuaishou.com 需要共享设备 id 可以存储到 cookie 中,否则也可以设置到 localStorage 中。
埋点的自增 id 是连续自增的数字,在计算埋点数量时,如果按照埋点生成时的时间戳排序,就可以根据自增 id 来发现埋点的缺失。如果只统计单个页面运行时埋点生成的情况,那么在页面关闭时生成和上报埋点就无法统计到,而页面关闭又恰恰是前端最容易丢失的场景,因此也需要通过本地存储来保存自增 id。因为自增 id 是随着埋点采集要频繁读写本地存储的,出于性能考虑使用 localStorage 要优于 cookie(localStorage 的读写性能约是 cookie 的 10 倍)。如果设备 id 是存储到 cookie,自增 id 存储到 localStorage 则会出现一个设备 id 对应多个域名的情况,埋点上报时需要带上域名信息,计算方式升级为下图表示:
这里有一点需要注意的,就是 localStorage 的读写是线程安全的,却不是进程安全的,也就是在多个 tab 页同时读写同一个 localStorage 的 key 时,有可能会冲突,为降低冲突的概率可以将自增 id 的 key 根据不同的埋点事件类型再做区分,埋点丢失计算时也需要多加一个维度。
有了丢失率的统计方案,还需要验证统计方案的可靠性,这个可以通过找业务特定场景,与业务的接口访问情况作对比来验证,就不过多叙述。
丢失率优化
要对埋点丢失率进行优化,需要从埋点丢失的问题入手,常见的埋点丢失问题分为以下两类:
- 技术问题:主要是埋点发送的方式,埋点发送异常的处理方式。
- 人为问题:网络抓包爬虫、黑产用户数据等。
埋点发送方式的优化
页面正常打开和运行时埋点的发送方式无论是 GET 请求还是 POST 请求,是通过 Image 的方式发起请求还是 XMLHttpRequest 请求,对埋点丢失是没什么影响的,但在页面关闭时会有差异,原因是页面关闭时浏览器会销毁当前页面的异步 http 请求线程,导致 XMLHttpRequest 的方式请求失败,而多数浏览器在加载 Image 时会延迟卸载页面从而使 Image 请求的方式成功率会更高些,这也是多数埋点 SDK 上报埋点的方式都是 Image 的原因之一(Image 请求也还有天然跨域、简单请求请求头小等优势)。
然而 Image 请求也不是万能的,如果有依赖请求响应信息的场景比如异常处理、采样控制等,则需要用正常的 XMLHttpRequest 请求。这种情况的优化方式是,如果用 POST 请求则可以使用 navigator.sendBeacon,如果 GET 请求可以在 beforeunload 或 unload 事件回调里通过创建短时间的空操作的循环来处理,示例代码如下:
window.addEventListener('beforeunload', function() {
// 埋点发送
});
window.addEventListener('unload', function() {
// no-op 循环
const prev = performance.now();
while(1) {
const now = performance.now();
if (now - prev >= 1000) {
break;
}
}
});
这种方式会影响下一个页面跳转,需要按需慎用,比如一些关键的下单、支付埋点可以使用,非必要埋点可以不需要。
埋点发送异常处理
由于网络不稳定,尤其是移动网络,埋点发送过程可能会发生异常,这时就需要监听异常对发送失败的埋点进行重试,可以通过监听 online 事件或者下次埋点发送成功时对失败埋点进行重试,如果页面关闭时网络依然异常,则可以通过 localStorage 存储到本地下次同域页面打开时发送,简易流程图如下:
这里为什么不对页面关闭前的埋点进行存储下次再上报呢,一个是如果页面关闭前发送的埋点即使是失败也很难获取到失败的状态,埋点也有可能是发送成功的,如果对其进行存储再上报就会导致埋点的重复上报,影响数据分析的指标,而如果页面关闭前不上报而是等下次打开再上报,可能埋点会短时间收集不到,影响数据消费的时效性。
同样的埋点异常其实也是包括了埋点发送成功但埋点响应异常的情况(比如网络抖动响应丢失),这种情况的重试也会导致埋点的重复,所以是否进行埋点异常重试也需要考虑服务端或者数仓是否有去重策略的支持。
网络抓包和黑产数据处理
在使用无头浏览器进行网络抓包时,也是会产生的埋点数据;黑产则是指一些用户通过虚假的行为去刷平台数据为自己盈利(比如伪造直播活动的活跃数据)。这些数据也会影响埋点丢失率的统计,干扰埋点数据的质量,常见的数据现象有:修改客户端时间戳,按照客户端事件戳对埋点进行排序计算时数据混乱;数据自增 id 重复,埋点实际上报数量和应有的埋点数据不一致;应用多开,一个设备 id 产生的埋点数据按照客户端时间戳排序呈间歇连续性等。
对于这些数据问题,一方面可以结合公司内部风控团队进行异常设备的黑名单处理,另一方面也可以根据数据规律在埋点丢失率统计时进行排除,来确保丢失率指标的稳定。
埋点数据准确性
最后简单介绍下对数据准确性的理解,前文就提到单个埋点就包含了 Who、When、Where、What、How 等信息,基于这些信息就可以对应用进行页面访问的流量、页面浏览的路径关系、行为归因等,如果数据准确性有问题,这些分析也会受影响。比较常见的数据准确性问题有埋点页面飘移、埋点入口混淆。
埋点页面飘移是指本应该在 A 页面上报的埋点,却携带成了 B 页面的信息,比如前端单页应用,在路由切换时一埋点需要依赖后端接口,埋点触发是在路由切换前,但实际上报时间是在页面切换后,这就可能导致埋点页面信息错误。
埋点入口混淆是指在页面的入口有多个,上报时不做区分,在数据分析时按照单个入口的数据分析发现数据异常。
这些埋点数据准确性的问题比较依赖埋点上报时做好埋点设计和埋点验证,就不过多说明。
总结
本文主要介绍埋点丢失率作为指标来衡量埋点质量,简单描述 Web 前端埋点丢失率统计的方案,并对埋点丢失常见的场景和优化方式进行分析。埋点数据更多是过程数据的分析,其数据质量可以帮助业务更准确的对自身产品进行归因分析,但对其质量的要求很多时候也并不需要特别高,只要埋点数量的趋势和比例正确即可。最后如果有感兴趣或者问题的同学也欢迎进一步留言交流。
暂无评论内容