字节跳动埋点数据流建设实践

技术

点击上方👆蓝字关注我们!

picture.image

作者|石伟,来自字节跳动数据平台开发套件团队

埋点数据流

埋点数据流在字节跳动

埋点数据流主要处理的数据是埋点,埋点也叫 Event Tracking,是数据和业务之间的桥梁,也是数据分析、推荐、运营的基石。

用户在使用 App 、小程序、 Web 等各种线上应用时产生的用户行为数据主要通过埋点的形式进行采集上报,按不同的来源可以分为:

  1. 客户端埋点
  2. Web端埋点
  3. 服务端埋点

picture.image

埋点通过埋点收集服务接收到 MQ,经过一系列的 Flink 实时 ETL 对埋点进行数据标准化、数据清洗、数据字段扩充、实时风控反作弊等处理,最终分发到不同的下游。下游主要包括推荐、广告、ABTest、行为分析系统、实时数仓、离线数仓等。因为埋点数据流处在整个数据处理链路的最上游,所以决定了 “稳定性”是埋点数据流最为关注的一点

字节跳动的埋点数据流规模

字节跳动埋点数据流的规模比较大,体现在以下几个方面:

  • 接入的业务数量很多,包括抖音、今日头条、西瓜视频、番茄小说在内的多个 App 和服务,都接入了埋点数据流。
  • 流量很大,当前字节跳动 埋点数据流峰值流量超过 1 亿每秒 ,每天处理超过万亿量级埋点,PB 级数据存储增量。
  • ETL 任务规模体量较大 ,在多个机房部署了超过 1000 个 Flink 任务和超过 1000 个 MQ Topic,使用了超过 50 万 Core CPU 资源,单个任务最大超过 12 万 Core CPU,单个 MQ Topic 最大达到 10000 个 partition。

那么在这么巨大的流量和任务规模下,埋点数据流主要处理的是哪些问题呢?我们来看几个具体的业务场景。

业务场景

UserAction ETL

在推荐场景中,由于埋点种类多、流量巨大,而推荐只关注其中部分埋点,因此需要通过 UserAction ETL 对埋点流进行处理,对这个场景来说有两个需求点:

  • 数据流的时效性
  • ETL 规则动态更新

picture.image

为了提升下流推荐系统的处理效率,我们在数据流配置ETL规则对推荐关注的埋点进行过滤,并对字段进行删减、映射、标准化等清洗处理,将埋点打上不同的动作类型标识,处理之后的埋点内部一般称为 UserAction。UserAction 与服务端展现、Feature 等数据会在推荐 Joiner 任务的分钟级窗口中进行拼接处理,产出 instance 训练样本。

举个例子:一个客户端的文章点赞埋点,描述了一个用户在某一个时间点对某一篇文章进行了点赞操作,这个埋点经过埋点收集服务进入 ETL 链路,通过 UserAction ETL 处理后,实时地进入推荐 Joiner 任务中拼接生成样本,更新推荐模型,从而提升用户的使用体验。

如果产出 UserAction 数据的 ETL 链路出现比较大的延迟,就不能在拼接窗口内及时地完成训练样本的拼接,可能会导致用户体验的下降,因此对于推荐来说,数据流的时效性是比较强的需求。而推荐模型的迭代和产品埋点的变动都可能导致 UserAction ETL 规则的变动,如果我们把这个 ETL 规则硬编码在代码中,每次修改都需要升级代码并重启相关的 Flink ETL 任务,这样会影响数据流的稳定性和数据的时效性,因此这个场景的另一个需求是 ETL 规则的动态更新。

数据分流

抖音的埋点 Topic 晚高峰超过一亿每秒,而下游电商、直播、短视频等不同业务关注的埋点都只是其中一部分。如果每个业务都分别使用一个 Flink 任务去消费抖音的全量埋点去过滤出自己关注的埋点,会消耗大量的计算资源,同时也会造成 MQ 集群带宽扇出非常严重,影响 MQ 集群的稳定性。

因此我们提供了数据分流服务,实现上是我们使用一个 Flink 任务去消费上游埋点 Topic,通过在任务中配置分流规则的方式,将各个业务关注的埋点分流到下游的小 Topic 中提供给各业务消费,减少不必要的资源开销,同时也降低了 MQ 集群出带宽。

分流需求大多对 SLA 有一定要求,断流和数据延迟可能会影响下流的推荐效果、广告收入以及数据报表更新等。另外随着业务的发展,实时数据需求日益增加,分流规则新增和修改变得非常频繁,如果每次规则变动都需要修改代码和重启任务会对下游造成较大影响,因此在数据分流这个场景,规则的动态更新也是比较强的需求。

picture.image

容灾降级

另一个场景是容灾降级。数据流容灾首先考虑的是防止单个机房级别的故障导致埋点数据流完全不可用,因此埋点数据流需要支持多机房的容灾部署。其次当出现机房级别的故障时,需要将故障机房的流量快速调度到可用机房实现服务的容灾恢复,因此需要埋点数据流具备机房间快速切流的能力。

picture.image

而数据流降级主要考虑的是埋点数据流容量不足以承载全部流量的场景,比如春晚活动、电商大促这类有较大突发流量的场景。为了保障链路的稳定性和可用性,需要服务具备主动或者被动的降级能力。

埋点数据流遇到的挑战

挑战主要是流量大和业务多导致的。流量大服务规模就大,不仅会导致成本治理的问题,还会带来单机故障多、性能瓶颈等因素引发的稳定性问题。而下游业务多、需求变化频繁,推荐、广告、实时数仓等下游业务对稳定性和实时性都有比较高的要求。

在流量大、业务多这样的背景下,如何保障埋点数据流稳定性的同时降低成本、提高效率,是埋点数据流稳定性治理和成本治理面对的挑战。

埋点数据流建设实践

上文我们了解了埋点数据流的业务场景和面对的挑战,接下来会介绍埋点数据流在 ETL 链路建设和容灾与降级能力上的一些实践。

ETL 链路建设

发展历程

埋点数据流 ETL 链路发展到现在主要经历了三个阶段。

第一个阶段是 2018 年以前,业务需求快速迭代的早期阶段 。那时我们主要使用 PyJStorm 与基于 Python 的规则引擎构建主要的流式处理链路。特点是比较灵活,可以快速支持业务的各种需求,伴随着埋点量的快速上涨,PyJStorm 暴露出很多稳定性和运维上的问题,性能也不足以支撑业务增长。2018 年内部开始大力推广 Flink,并且针对大量旧任务使用 PyJStorm 的情况提供了 PyJStorm 到 PyFlink 的兼容适配,流式任务托管平台的建设一定程度上也解决了流式任务运维管理问题,数据流 ETL 链路也在 2018 年全面迁移到了 PyFlink,进入到 Flink 流式计算的新时代。

第二个阶段是 2018 年到 2020 年,随着流量的进一步上涨,PyFlink 和 Kafka 的性能瓶颈以及当时使用的 JSON 数据格式带来的性能和数据质量问题纷纷显现出来。 与此同时,下流业务对数据延迟、数据质量的敏感程度与日俱增。我们不仅对一些痛点进行了针对性优化,还花费一年多的时间将整个 ETL 链路从 PyFlink 切换到 Java Flink,使用基于 Groovy 的规则引擎替换了基于 Python 的规则引擎,使用 Protobuf 替代了 JSON,新链路相比旧链路性能提升了数倍。同时大数据开发平台和流量平台的建设提升了埋点数据流在任务开发、ETL 规则管理、埋点管理、多机房容灾降级等多方面的能力。

第三个阶段是从 2021 年开始至今,进一步提升数据流 ETL 链路的性能和稳定性,在满足流量增长和需求增长的同时,降低资源成本和运维成本是这一阶段的主要目标 。我们主要从三个方面进行了优化:

  • 优化了引擎性能 ,随着流量和 ETL 规则的不断增加,我们基于 Groovy 的规则引擎使用的资源也在不断增加,所以基于 Janino 对规则引擎进行了重构,引擎的性能得到了十倍的提升。
  • 基于流量平台建设了一套比较完善的埋点治理体系 ,通过埋点下线、埋点管控、埋点采样等手段降低埋点成本。
  • 将链路进行了分级 ,不同的等级的链路保障不同的 SLA,在资源不足的情况下,优先保障高优链路。

接下来是我们 2018 至 2020 年之间埋点数据流 ETL 链路建设的一些具体实践。

基于规则引擎的 Flink ETL

在介绍业务场景时,提到我们一个主要的需求是 ETL 规则的动态更新,那么我们来看一下埋点数据流 Flink ETL 任务是如何基于规则引擎支持动态更新的,如何在不重启任务的情况下,实时的更新上下游的 Schema 信息、规则的处理逻辑以及修改路由拓扑。

picture.image

首先,我们在流量平台上配置了上下游数据集的拓扑关系、Schema 和 ETL 规则,然后通过 ConfigCenter 将这些元数据发送给 Flink ETL Job,每个 Flink ETL Job 的 TaskManager 都有一个 Meta Updater 更新线程,更新线程每分钟通过 RPC 请求从流量平台拉取并更新相关的元数据,Source operator 从 MQ Topic 中消费到的数据传入 ProcessFunction,根据 MQ Topic 对应的 Schema 信息反序列化为 InputMessage,然后进入到规则引擎中,通过规则索引算法匹配出需要运行的规则,每条规则我们抽象为一个 Filter 模块和一个 Action 模块,Fliter 和 Action 都支持 UDF,Filter 筛选命中后,会通过 Action 模块对数据进行字段的映射和清洗,然后输出到 OutputMessage 中,每条规则也指定了对应的下游数据集,路由信息也会一并写出。

当 OutputMessage 输出到 Slink 后,Slink 根据其中的路由信息将数据发送到 SlinkManager 管理的不同的 Client 中,然后由对应的 Client 发送到下游的 MQ 中。

规则引擎

规则引擎为埋点数据流 ETL 链路提供了动态更新规则的能力,而埋点数据流 Flink ETL Job 使用的规则引擎也经历了从 Python 到 Groovy 再到 Janino 的迭代。

picture.image

由于 Python 脚本语言本身的灵活性,基于 Python 实现动态加载规则比较简单。通过 Compile 函数可以将一段代码片段编译成字节代码,再通过 eval 函数进行调用就可以实现。但 Python 规则引擎存在性能较弱、规则缺乏管理等问题。

迁移到 Java Flink 后,在流量平台上统一管理运维 ETL 规则以及 schema、数据集等元数据,用户在流量平台编辑相应的 ETL 规则,从前端发送到后端,经过一系列的校验最终保存为逻辑规则。引擎会将这个逻辑规则编译为实际执行的物理规则,基于 Groovy 的引擎通过 GroovyClassLoader 动态加载规则和对应的 UDF。虽然 Groovy 引擎性能比 Python 引擎提升了多倍,但 Groovy 本身也存在额外的性能开销,因此我们又借助 Janino 可以动态高效地编译 Java 代码直接执行的能力,将 Groovy 替换成了 Janino,同时也将处理 Protobuf 数据时使用的 DynamicMessage 替换成了 GeneratedMessage,整体性能提升了 10 倍。

除了规则引擎的迭代,我们在平台侧的测试发布和监控方面也做了很多建设。测试发布环节支持了规则的线下测试,线上调试,以及灰度发布的功能。监控环节支持了字段、规则、任务等不同粒度的异常监控,如规则的流量波动报警、任务的资源报警等。

Flink 拆分任务

规则引擎的应用解决了埋点数据流 ETL 链路如何快速响应业务需求的问题,实现了 ETL 规则的动态更新,从而修改 ETL 规则不需要修改代码和重启任务。

picture.image

但规则引擎本身的迭代、流量增长导致的资源扩容等场景,还是需要升级重启 Flink 任务,导致下游断流。

除了重启断流外,大任务还可能在重启时遇到启动慢、队列资源不足或者资源碎片导致起不来等情况。

针对这些痛点我们上线了 Flink 拆分任务,本质上是将一个大任务拆分为一组子任务,每个子任务按比例去消费上游 Topic 的部分 Partition,按相同的逻辑处理后再分别写出到下游 Topic。

举个例子:上游 Topic 有 200 个 Partition,我们在一站式开发平台上去配置 Flink 拆分任务时只需要指定每个子任务的流量比例,每个子任务就能自动计算出它需要消费的 topic partition 区间,其余参数也支持按流量比例自动调整。

拆分任务的应用使得数据流除了规则粒度的灰度发布能力之外,还具备了 Job 粒度的灰度发布能力,升级扩容的时候不会发生断流,上线的风险更可控。同时由于拆分任务的各子任务是独立的,因此单个子任务出现反压、Failover 对下游的影响更小。另一个优点是,单个子任务的资源使用量更小,资源可以同时在多个队列进行灵活的部署。

容灾与降级能力建设

说到 ETL 链路建设,埋点数据流在容灾与降级能力建设方面也进行了一些实践。

picture.image

首先是容灾能力的建设 ,埋点数据流在 Flink、MQ、Yarn、HDFS 等组件支持多机房容灾的基础上完成了多机房容灾部署,并准备了多种流量调度的预案。

正常情况下流量会均匀打到多个机房,MQ 在多个机房间同步,Flink ETL Job 默认从本地 MQ 进行消费,如果某个机房出现故障,我们根据情况可以选择通过配置下发的方式从客户端将流量调度到其他非受灾机房,也可以在 CDN 侧将流量调度到其他非受灾机房。埋点数据流 ETL 链路可以分钟级地进入容灾模式,迅速将故障机房的 Flink Job 切换到可用的机房。

其次是服务降级能力的建设 ,主要包含服务端降级策略和客户端降级策略。服务端降级策略主要通过 LB 限流、客户端进行退避重试的机制来实现,客户端降级策略通过配置下发可以降低埋点的上报频率。

举个例子:在春晚活动中参与的用户很多,口播期间更是有着非常巨大的流量洪峰,2021 年春晚活动期间为了应对口播期间的流量洪峰,埋点数据流开启了客户端的降级策略,动态降低了一定比例用户的埋点上报频率,在口播期间不上报,口播结束后迅速恢复上报。在降级场景下,下游的指标计算是通过消费未降级用户上报的埋点去估算整体指标。目前我们在此基础上进行了优化,客户端目前的降级策略可以更近一步的根据埋点的分级信息去保障高优的埋点不降级,这样可以在活动场景下保障活动相关的埋点不降级的上报,支持下游指标的准确计算。


活动推荐

8 月 18 日,火山引擎开发者社区技术大讲堂第四期将为大家从开源大数据生态和源于字节跳动内部的智能实时湖仓两个方面详细介绍如何构建企业级数据湖仓,分享火山引擎 LAS 和 EMR 产品的架构与实践,扫描下方

二维码

或点击【

阅读原文

】即可报名!

picture.image

89
0
0
0
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论