用户行为分析埋点实践
一、前言
大数据应用一般会有采集、加工、存储、计算及可视化这几个环节。其中采集做为源头,在确保全面、准确、及时的前提下,最终加工出来的指标结果才是有价值的。
而埋点作为一种重要的采集手段,可以将用户行为信息转化为数据资产,为产品分析、业务决策、广告推荐等提供可靠的流量数据支持。
在业务需求少的情况下,可以运用一些简单的方法快速采集用户行为。但如果业务线、终端众多,数据需求多样,就需要设计好埋点模型和采集规范,工具化、平台化、流程化的管理来保证埋点的质量。
二、事件模型
首次需要思考的是,如何描述和记录用户的一次行为。这里我们使用的事件模型,即:
- who
访客标识、设备指纹、登录ID
- when
事件发生时间、上报时间
- where
设备环境、网络环境、业务环境等
- what
事件标识、事件参数
我们设计了可以承载以上信息的日志模型,并保持必要的可扩展性,将数据映射到schema的各个字段中,一次行为便完整的记录下来。
三、采集方式
数据模型设计好后,接下来要考虑的是如何将客户端内的用户行为数据采集到服务端,这里主要依赖于客户端提供的监听能力。
目前有赞支持两种采集方式:
3.1 无痕埋点(或全埋点)
利用浏览器或APP自带的监听方式,对用户的浏览页面、点击等行为进行收集,可以收集到的信息主要有:
- 页面的url、APP的包名等
- 点击元素的xpath路径、title或约定的dom元素
无痕埋点的优势有:
- 前端接入成本低,不需要额外开发
- 用户动作收集完整,不会漏失
但同时也会存在以下问题:
- 有用、没用的数据都会收集
- 无法采集到特殊的行为动作、业务参数
- 采集到的信息需要进行二次标注,才可以被用户识别
- 当按钮的位置不固定、名称存在重复或页面重构时,无法做到准确的标识
无痕埋点在有赞一般用来做粗粒度的快速业务探索。
3.2 代码埋点
代码埋点是指依赖前端同学,自定义监听和收集处理。代码埋点的优势有:
- 事件标识明确
- 业务参数丰富
- 事件的触发方式可以灵活自定义
- 分析更方便、精确
随之而来的是以下问题:
- 前端代码的开发、管理成本
- 只能收集到事件上线之后的数据
在业务需求复杂,无痕埋点收集到的信息无法支持分析时,就需要进行代码埋点。
四、埋点sdk
为简化前端同学的埋点开发工作,使其只需要关注于业务本身,并对埋点的一些约定进行必要的约束,有赞开发了多个端(js/小程序/android/ios/java)的埋点sdk。
sdk默认支持以下功能:
- 访客标识管理
- 会话管理
- 环境参数默认收集
- 参数的生命周期管理
- 默认事件的收集
- 跨端的sdk通信(如app嵌套h5页面)
- 内部业务的特殊处理逻辑
- 日志的格式化、合并、生命周期管理
- 日志的上报机制
前端同学通过sdk提供的接口进行开发,只需要关注:
- SDK的初始化配置
- 事件怎么标识
- 事件需要哪些参数
- 事件如何触发
五、日志中间层
数据收集上来后,原始日志还处于非常精简的状态,需要进一步加工成日志中间层,主要有以下几个环节:
- 批量上报的日志拆分
- 日志模型的格式化处理
- 信息的二次加工和维度扩展
如IP、http_agent的解析等
- 异常流量的清洗
- 会话信息的补充
如落地页、二跳页、停留时长的计算
- 按业务拆分日志流和日志表
实时流中间层是以JSON格式存储在kafka中,并且提供对应的JavaBean类,方便实时任务开发解析处理,并且也可以与streamSql相结合使用。
离线中间层是存储在同一个表中,字段与实时流格式保持一致,以日期和业务作为分区条件,并会自动创建所有业务的视图表,方便中间层的统一调整以及数仓的权限管理。
到这个阶段,有了通用的日志模型和sdk,埋点工作可以标准化的开展起来。但随着承接的业务越来越多,更多的问题在等待着我们。
六、位置追踪规范
在精细化运营及算法推荐等应用场景下,需要非常精确掌握行为发生的位置场所。如果每个业务都自定义一套标识方式,那么每次分析工作都需要重新开发,无法复用逻辑,这将极大的浪费开发资源,因此需要制定出统一的位置规范。
我们将位置分成了四个粒度:
- 业务
- 页面域(包括页面类型和页面id)
- 组件域(如图中红色部分,包括组件类型和组件序号)
- 展位域(如图中绿色部分,包括展位标识和展位序号)
业务 + 页面域 + 组件域 + 展位域 + 页面随机码,可以唯一确定一个访问的位置。基于位置分解出来的维度组合,可以很方便的分析出各个粒度的访问、曝光、点击数据。
类似的还有算法追踪规范,在此不作展开。
七、埋点管理平台
有赞的早期阶段,所有业务的埋点方案都是记录在wiki中。随着业务线和项目的快速增加,wiki记录的弊端也逐渐暴露出来:
- 登记格式无法统一,关键信息容易缺失
- 事件查找不便,分析同学不知道已有哪些事件
- 迭代更新事件无法合并,同时存在多份信息
- 开发进度、测试进度无法监控
- 埋点质量问题无法快速对接
基于开发中碰到的各类问题,愈发的让我们意识到平台建设的必要性,主要涉及以下几点能力:
- 埋点元数据的管理及开放能力
- 埋点流程的管理能力
当有了埋点元数据,可以延伸出来更多的操作空间,如:
- 埋点的自动测试
- 埋点的自助分析
- 埋点的开发提示
- 埋点的质量监控
7.1 埋点元数据管理
根据事件模型及位置追踪规范,我们将元数据的组成分为业务
、页面
、组件
、展位
、事件
- 业务:由业务类型(微商城、零售等)和SDK类型(js/小程序/android/ios/java)唯一确定。页面、组件、展位、事件等属于且仅属于一个业务。
- 页面:具有相同页面结构的一类网页或者移动端页面。
- 组件:页面内的区块,也包括跨页面的可复用区块。
- 展位:组件内最细粒度的坑位,有三种位置标识,即递增(顺序排列)、固定(特定的位置)和正则标识(复杂布局)。
- 事件:埋点基本单元,对应用户的一个动作,比如进入页面、点击按钮、商品曝光等,每个事件还可以定义独有的参数。按其归属,可以分为全局事件、页面事件和组件事件。
7.2 项目流程管理
当一个新项目启动时,会有对应的一批埋点需求,为了方便PM管理与追踪进度,以及日后的质量反馈,需要有项目级的管理功能来支持。
埋点项目可以涉及多个业务,由PM/前端/数据/BI/测试等共同参与,并跟踪从立项到评审、设计、开发、联调、上线等各个阶段。埋点项目组织了埋点需求相关的页面、组件、展位和事件。
7.3 埋点测试
上线前的埋点测试直接关系到数据质量,早期测试是使用抓包工具,每个事件肉眼判断,不仅效率低下,而且容易判断错误或遗漏。 因此当元数据收集完成之后,为了解决以上问题,我们设计了埋点在线测试功能。
1、测试用户输入项目和用户标识,在线测试模块会将用户标识存储到redis中
2、校验任务消费实时日志,并定时同步埋点元数据和用户标识集合,以此校验日志并收集到埋点平台中
3、将收集到的实时日志返回给用户
4、项目已测试的事件进行汇总,生成概览数据
日志检测项
- 日志格式是否标准
- 通用业务参数是否收集完整
- 业务、页面、组件、事件是否登记
- 事件参数是否缺失,格式是否符合要求
检测等级分为Warning/Error级别,会有相应的错误信息。
测试结果
使用不同图标来标识检测状态,并且给出本轮测试的汇总数据。
项目测试概览
汇总项目中所有事件的测试状态,并给出失败事件的明细日志。
用户标识
为了方便测试同学快速找到自己的用户标识,平台提供了pc链接、手机扫码、手机号等快捷查找方式。
7.4 质量监控
测试的覆盖面不全,或者系统日常的开发迭代,都有可能会导致线上埋点的质量问题。早期常常会出现这样的场景:
开发同学误修改一段代码,导致线上埋点事件丢失,很长一段时间后,运营同学发现某个指标波动异常,逐层查询,最终定位问题,但这期间的数据已无法恢复。
为了避免这种情况一而再,再而三的发生,就需要对线上的流量日志实时监控起来,并且第一时间反馈到相关负责人。
详细内容将在下篇埋点分享中介绍
7.5 埋点分析
早期埋点上线后,分析同学会根据埋点元数据,通过写sql或代码的方式,处理实时流和离线表来查询出想要的指标。其中有不少数据需求都是比较通用的场景:
查询某个事件按一定维度pv/uv的指标或接口,分析多个行为的转化漏斗,某类渠道的归因分析
这部分可以通过通用分析模型自动处理,从而提升分析效率。
详细内容将在下篇埋点分享中介绍
八、埋点开发流程
早期埋点的设计与对接工作都是由数据组同学来支持,随着业务规模的不断扩大,已经逐渐成为开发的瓶颈。
依托于埋点平台提供出来的能力和工具,我们规范了埋点项目的开发流程,改由PM做为流程的负责人,协调各方资源,并把控各阶段的进度。
开发流程如上图:
1、PM在PRD中明确数据需求,给出指标的定义、获取指标的方式等。
2、PM确认开发资源及排期(前端、分析同学)
3、相关同学设计并在平台上登记埋点方案,设计完成后前端、分析同学对埋点方案进行评估
4、前端同学根据埋点方案进行开发
5、开发完成后,前端和PM对埋点进行测试,确保上线前所有事件均测试通过
6、分析同学提前准确代码,埋点上线后第一时间产出相关指标
7、若相关同学接收到埋点平台报警时,需要及时处理问题并反馈影响
通过流程和赋能,数据组可以节省出人力,投入到其它需要发挥数据价值的地方。
核心业务流程中的埋点仍由数据组介入管理,需要严格保证其质量。
九、埋点底层框架
日志流转主要环节如上图:
1、前端监控用户行为,收集并通过http请求上报
2、NIO高并发日志接收服务将日志转发到rsyslog服务器中,再通过logstash转发到kafka原始日志中
3、JAVA端埋点通过异步请求将日志上报到nsq中,再通过flume实时同步到kafka原始日志中
4、flink实时ETl任务将原始日志加工成标准中间层格式,并继续落地到kafka
5、kafka日志通过flume同步到hdfs,按小时切割文件
6、hdfs日志文件通过spark小时级任务转化成hive表
十、未来展望
目前埋点平台支撑了有赞微商城、零售、美业、精选、分销、有赞云、内部系统等十几条业务线,平均每月20+新项目的项目,在支持已有流量需求的同时,我们也在思考如何进一步提升开发效率和发挥数据价值:
- 更加友好的平台引导,让不懂埋点的小白用户能快速上手
- 前端开发效率提升,sdk与前端框架结合,可视化、配置化埋点
- 降低sdk上报的丢失率
- 全端的用户日志快捷查找,提升测试和排查问题效率
- 更智能的质量管理,快速定位和解决埋点问题
- 实时日志中间层与业务域的维度扩展
- 无痕埋点的页面自动归类标识
- 分析效率提升,与指标库打通,以及更易用的转化和归因模型来快速定位问题
- 支持算法ABTest实验分析
常见问题
我们收集日志,目的还是为了分析用户行为,挖掘潜在价值,最终能优化产品体验。因此,“高质量”是最基本要求,这是保证分析效果准确性的基石。那么,常见的质量问题有哪些呢?
- 事件重复&丢失。重复是由于SDK自身或者前端开发疏忽的问题,导致相同事件重复发送;丢失可能是设备、网络原因,或者是开发者漏埋导致。
- 事件参数错误。常见的情况有:”必传而未传“、”非空而为空“、”值类型不对“、”值内容不对”等。
- 前端常见错误。比如值为“undefined”、“null”,通常是前端代码bug导致的值错误。
- 事件断流。这种case经常发生,前端在做改造升级的时候,可能导致事件上报不规范,或者误下线。
保障机制
针对埋点质量问题,我们尝试以下的保障机制,去解决。从业务开发的过程出发,在不同阶段提供服务支持,形成一个解决问题的闭环,保障日志处于高质量状态。
准确登记
业务需要根据“埋点规范”,规划好页面、组件和事件,并且在埋点平台上准确地登记。登记的信息越全,内容越细,越有利于自动化判定日志的准确性。目前我们登记的要素有:
- 页面/组件类型,登记该元素的业务标识,以及是否有业务ID。日志上报时,会有对应的字段记录该信息。
- 事件信息,事件的名称/标识/描述,所属页面/组件,以及所处状态等信息。
- 事件参数,属于该事件的一系列业务参数,比如一个点击事件的参数可能是被点击的商品的ID。对于参数的登记,我们支持标识/类型/是否必传/参数结构的设置。其中类型支持int/string/float/list/map,用于申明值内容结构;参数结构支持对复杂的数据类型,进一步定义其细节。
实时校验
做好了埋点的登记工作,开发就可以按照埋点方案做相应的开发了。如何快速验证上报日志的准确性,以及如何及时发现线上问题,是我们面临的直接问题。因此,我们做了实时校验。除了实时外,校验还需要考虑更新及时性/完备性/扩展性,避免规范或校验点的变更,带来频繁的修改代码或重启任务。另外,对于校验结果,还需要要做到可解释/可沉淀/可分析。
对于实时性,我们采用Flink开发校验模块,实现秒级日志校验;校验规则更新的及时性上,每分钟从埋点平台同步;可沉淀,校验结果除了推送给测试工具外,还会落到druid,用于后续分析。这些点的思路比较直接,就不赘述了。下面着重介绍下其他考虑点:
完备性/扩展性
完备性比较好理解,校验需要支持的,除了底层的埋点规范外,还有分业务的页面/组件的合法性、事件关联页面/组件的情况、事件参数格式内容等;扩展性的考虑点在于,校验点会持续不断完善,如何“以不变应万变”。这点上,主要思路有两个:
1. 通过分析校验规则,抽象语义,我们设定以下语法(示例):
{
"compare":"length",
"condition":[
"sdk_type",
"in",
[
"iOS",
"Android",
"js"
]
],
"assert":"true",
"assert_fail":"ERROR",
"value":36,
"key":"uuid",
"fail_msg":"did/uuid invalid",
"require":1
}
本示例的含义:在sdk_type为iOS、Android或js的情况下,检查uuid参数,保证其是必传的字符串,且长度是36,如果不是则是ERROR级错误,错误信息为“did/uuid invalid”。具体字段说明:
- key:参数名
- value_type:参数值类型,默认为string,可指定int
- compare:参数值检查方式,支持:
- in:在一系列值内
- length:对于字符串类型,指定长度
- regex:对字符串类型,指定正则
- value:参数值约束,对于compare=in是一个list;对于compare=length是一个数值;对于compare=regex是一个正则字符串
- assert:检查结果需符合的值,true或false
- assertfail:检查失败给出的异常等级,WARNING、ERROR、TESTWARNING
- fail_msg:检查失败给出的错误信息
- condition:检查前置条件,符合该条件才进行检查。
- require:该参数是否必须,非必需情况下,若为空则不检查
2. 开关&配置化
不同时期,校验关注的点可能是不一样的,不同阶段,校验的逻辑也会有所区别。比如初期在问题重灾区,我们对未登记的事件,没有直接发送异常告警,但后期会;在新校验点试验阶段,其校验登记会设定为WARNING或TEST_WARNING,而上线稳定后,可能会改成ERROR。因此,在实现中,就特别注意使用开关或配置,达到功能点的可定制。
可解释/可分析
校验发现了问题,是为了解决问题。因此对结果,要求是可解释的:在哪个层次,哪个参数发生什么样的错误,原因是啥;可分析的:分析不同级别、不同维度组合的异常分布、走势,便于集中定位和解决问题。
实现上,我们会对校验的层次、范围、结果等级作区分,对于每条日志可能产出多条校验结果(1+n)。 其中的n,是指不同层次和字段,可能会有ERROR/WARNING/TEST_WARNING状态;1指的是整体上,会有个最严重的状态汇总。
简化后的校验结果格式,是这样的(包含多个关键维度,维度所处层级,问题字段、级别等):
{
"log_id":"571531737e29586094318d3bf64e9407",
"timestamp":1556174577000,
"event_type":"click",
"sdk_version":"0.7.7",
"sdk_type":"js",
"display_url":"url",
"scope":"OVERALL",
"field1":"",
"field2":"",
"status":"SUCCESS",
"value":""
}
有了这样的校验结果,可以做很多事:埋点错误重灾区、错误趋势、原因分布等,实现可解释和可分析。
定时监控
除了上线前的把关,事后的监控也是很有必要的。从质量角度,关心规范的实际约束情况;从流量角度,特别关注事件断流和异常波动情况;另外,业务上有很多约束,也需要去做监控。
基于实时校验结果,我们做到分钟级的质量和流量监控,在业务层面,会有小时级的个性化监控。
监控的“低误报”是一个很重要的考虑点,泛滥的监控等于没监控,在这点上,我们对监控做了一系列优化,如设定流量门槛、结合历史流量饱和度判定断流等。
专项优化
发现问题是手段,解决问题才是目的。
对于质量问题,会反馈到业务方去整改;除了业务上,还有许多基础SDK或开发上的通病问题,需要单独去做分析,成立专项,集中整改。比如SDK的重复率和丢失率问题,需要具体分析问题,推动底层优化。
这类工作主要是:问题分析>追根溯源>确定解法>持续跟踪。这里边涉及到许多特定场景的细节问题,就不展开讲了。
评估模型
如何去评估质量状态,是一个值得深思的问题。如果不能正确评价,就会摸不清重点,不知道如何优化,以及状态是在改善还是恶化。
我们的衡量维度目前是这样的:
需要注意的是,各维度的权重,不应该是一成不变的,而要随着问题的重点而调整;甚至考虑的问题,也要不断去做优化,加入新的考量点。
有了一套这样的评估模型,质量的状态就可以以“分数”的形式直观地呈现。对于问题的关键点,也可以有重点有方向地去解决。
质量中心
日常的质量问题,需要统一的呈现和管理,便于业务方有整体的感知,集中解决。
此外,对于汇总信息,也会以日报/周报的形式提醒到。
现状&规划
在以上介绍的一整套体系化的质量保障工作下,有赞的埋点质量有了大幅度提升。从状态未知到数字化的衡量;从缺少管理到集中化的呈现,并能提供优化辅助功能;从“不及格”的低质量到绝大部分问题被解决,质量问题已经不是业务分析的绊脚石。
我们的质量保障工作已经取得不错的成果,并形成良性的循环。但是还有许多可以优化的点:
- 支持更丰富的校验功能,将复杂的校验配置可视化
- 结合流量预测做监控告警,优化误报率
- 评估模型优化,结合现状,调整维度和权重
- 更完善的质量中心,集成快捷的优化操作
- 明确奖惩机制,推动业务方主动关心和优化质量问题,让前文提到的闭环,顺畅运行
通过这些方向的努力,相信有赞的埋点质量会持续保持高质量状态,更有力地为业务分析保驾护航。
来源:https://tech.youzan.com/track-1/
来源:https://tech.youzan.com/mai-dian-zhi-liang-bao-zhang/
评论