深度介绍Flink在字节跳动数据流的实践

2022年01月14日 阅读数:2
这篇文章主要向大家介绍深度介绍Flink在字节跳动数据流的实践,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

本文是字节跳动数据平台开发套件团队在1月9日Flink Forward Asia 2021: Flink Forward 峰会上的演讲,着重分享了Flink在字节跳动数据流的实践。前端

字节跳动数据流的业务背景

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

用户在使用App、小程序、Web等各类线上应用时产生的行为,主要经过埋点的形式进行采集上报,按不一样的来源分为客户端埋点、Web端埋点、服务端埋点。后端

不一样来源的埋点都经过数据流的日志采集服务接收到MQ,而后通过一系列的Flink实时ETL对埋点进行数据标准化、数据清洗、实时风控反做弊等处理,最终分发到下游,主要的下游包括ABTest、推荐、行为分析系统、实时数仓、离线数仓。安全

因此,若是用一句话来归纳数据流主要业务,其实就是埋点的收集、清洗、分发。网络

目前在字节跳动,清洗和分发环节是基于Flink搭建的。架构

深度介绍Flink在字节跳动数据流的实践_数据

01 - 数据流业务规模

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

02 - 数据流业务挑战

字节跳动数据流ETL遇到的挑战主要有四点:app

  • 第一点流量大,任务规模大
  • 第二点,处在全部产品数据链路最上游,下游业务多,ETL需求变化频繁
  • 第三点高SLA要求,下游推荐、实时数仓等业务对稳定性和时效性有比较高的要求。
  • 最后一点,在流量大、业务多、SLA要求高的状况下,针对流量、成本、SLA保障等多维度的综合治理也面临挑战。

下面从两个数据流业务场景中介绍一下咱们遇到的业务挑战。运维

一、UserAction ETL场景

在UserAction ETL场景中,咱们遇到的核心需求是:种类繁多且流量巨大的客户端埋点需求和ETL规则动态更新的需求。分布式

在字节内部,客户端的埋点种类繁多且流量巨大,而推荐关注的只是部分埋点,所以为了提高下游推荐系统处理效率,会在数据流配置一些ETL规则,对埋点进行过滤,并对字段进行删减、映射、标准化之类的清洗处理,将埋点打上不一样的动做类型标识。ide

处理以后的埋点通常称之为UserAction,UserAction数据会和服务端展示等数据在推荐Joiner任务的分钟级窗口中进行拼接Join,产出Instance训练样本。

深度介绍Flink在字节跳动数据流的实践_链路_02

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

若是产出UserAction数据的ETL链路出现比较大的延迟,那么就不能在窗口内及时完成拼接,可能致使用户体验降低。

所以对于推荐来讲,数据流的时效性是一个强需求

而推荐模型的迭代、产品埋点的变更均可能致使UserAction的ETL规则的变更。若是ETL规则硬编码在代码中,每次修改都须要升级代码并重启Flink Job,会影响数据流稳定性和数据的时效性。所以,这个场景的另外一个需求就是ETL规则的动态更新

二、数据分流场景

目前,抖音业务的埋点Topic晚高峰流量超过1亿/秒,而下游电商、直播、短视频等不一样业务的实时数仓关注的埋点范围实际上都只是其中的一小部分。

若是各业务分别使用一个Flink任务,消费抖音埋点Topic,过滤消费各自关注的埋点,须要消耗大量Yarn资源,同时会形成MQ集群带宽扇出严重,影响MQ集群的稳定性。

所以,数据流提供了数据分流服务,使用一个Flink任务消费上游埋点Topic,而后经过配置规则的方式,将各业务关注的埋点分流到下游小Topic中,再提供给各个业务消费。这样就减小了没必要要的反序列化开销,同时下降了MQ集群带宽扇出比例。

深度介绍Flink在字节跳动数据流的实践_数据_03

在数据分流场景中,核心须要解决的是高稳定的SLA。由于断流、数据延迟可能会影响推荐效果、广告收入、实时数据报表。

同时随着业务发展,实时数据需求日益增长,分流规则新增和修改也会日益频繁。若是每次规则变更都须要修改代码并重启Flink Job,会影响不少下游,所以分流规则的动态更新也是这一场景中的强需求。

字节跳动数据流实践

01 - 数据流ETL链路建设

字节跳动数据流ETL链路建设主要经历了三个阶段:

  • 第一阶段是2018年之前——业务需求快速迭代的早期阶段

主要使用PyJStorm和基于Python的规则引擎构建主要的流式数据处理链路。其特色是比较灵活,能够快速支持业务需求。

但随着埋点流量快速上涨,PyJStorm暴露出不少稳定性和运维上的问题,性能也不足以支撑业务的增加。

2018年,公司内部开始大力推广Flink,而且针对大量旧任务使用PyJStorm的状况,提供了PyJStormPyFlink的兼容适配。流式任务托管平台的建设必定程度上解决了流式任务运维管理的问题。数据流ETL链路也在2018年全面迁移到了PyFlink,进入了流式计算的新时代。

  • 第二个阶段是2018至2020年

随着流量的进一步上涨,PyFlink和Kafka的性能瓶颈、以及JSON数据格式带来的性能和数据质量问题都一一显现出来,与此同时下游业务对延迟、数据质量的敏感程度倒是与日俱增。

因而,咱们一方面对一些痛点进行了针对性的优化。另外一方面,花费1年多的时间将整个ETL链路从PyFlink切换到了Java Flink,使用基于Groovy的规则引擎替换了基于Python的规则引擎,使用ProtoBuf替换了JSON

数据流ETL新链路,相比旧链路性能提高了1倍

与此同时,一站式大数据开发平台和流量平台的建设提高了数据流在任务开发运维、ETL规则管理、埋点元数据管理、多机房容灾降级等多方面的能力。

  • 第三个阶段是从2021年开始

在全球资源供应紧张的背景下,进一步提高数据流ETL性能和稳定性,知足流量增加和需求增加的同时,下降资源成本和运维成本,是这一阶段的主要目标。咱们主要从三个方面进行了优化:

  1. 优化引擎性能。随着流量和ETL规则的不断增长,基于Groovy的规则引擎使用的资源也不断增长,因而咱们基于Janino进行了重构,引擎性能获得数倍提高。
  2. 优化埋点治理体系。咱们基于流量平台建设了一套比较完善的埋点治理体系,经过无用埋点下线、埋点采样等手段下降埋点成本。
  3. 优化链路。咱们进行了链路分级,不一样等级的链路保障不一样的SLA,在资源不足的状况下优先保障高优埋点链路。

从2018年到2020年,咱们持续在数据流Flink ETL Job应对需求挑战上取得了一些实践效果。

下图展现了数据流Flink ETL Job是如何支持动态更新的,在不重启任务的状况下,实时更新上下游Schema、规则处理逻辑、修改路由拓扑。

深度介绍Flink在字节跳动数据流的实践_flink_04

流量平台Config Center为数据流Flink ETL Job提供上下游数据集拓扑关系、Schema、ETL规则和UDF等元数据。

数据流Flink ETL Job中的每一个TaskManager中会有一个Meta Updater更新线程,更新线程每分钟经过RPC请求从流量平台拉取并更新相关元数据。

Source将从MQ中消费到的数据传入ProcessFunction,根据MQ对应的Schema反序列化为InputMessage,而后进入规则引擎中,经过规则索引匹配出须要运行的规则,每条规则抽象为一个Filter模块和一个action模块,Filter和action都支持UDF ,Filter筛选命中后,经过action模块对输入数据进行字段映射和清洗,而后写出到OutputMessage中。

每条规则也指定了对应的下游数据集,路由信息也会一并写出到OutputMessageOutputMessage输出到Sink后,Sink根据OutputMessage中的路由信息将数据发送到SinkManager管理的Client,由对应的Client发送到下游MQ。

这里解释一下咱们为何让每一个TaskManager经过一个MetaData updater定时去更新元数据,而不是经过增长一条元数据流来更新。这么作的缘由主要是由于使用元数据流更新的方式须要开启Checkpoint以保存元数据的状态,而在字节跳动数据流这样的大流量场景下,开启Checkpoint会致使在Failover时产生大量重复数据,下游没法接受。

一、规则引擎的解决方案

数据流Flink ETL Job使用的规则引擎经历了从Python到Groovy再到Janino的迭代。规则引擎对于数据流来讲最主要的就是提供动态更新ETL规则的能力。

Python因为脚本语言自己的灵活性,动态加载规则实现起来比较简单,经过Compile函数能够将一段规则代码片断编译成字节代码,再经过eval函数进行调用便可。但存在性能较低,规则缺少管理的问题。

迁移到Java Flink后,咱们在流量平台上统一管理ETL规则、Schema、数据集等元数据。用户在流量平台编辑ETL规则,规则从前端视图发送到后端,通过一系列校验后保存为逻辑规则,引擎将逻辑规则编译为物理规则运行。Groovy自己兼容Java,因此咱们能够经过GroovyClassLoader动态的加载规则、UDF。

但使用Groovy,虽然性能比Python提升了不少倍,但额外的开销仍比较大,所以咱们又借助Janino能够高效动态编译Java类并加载到JVM直接执行的能力,将Groovy替换为Janino。

除了规则引擎的迭代,咱们在平台侧的测试、发布、监控和报警方面也作了不少建设。

测试发布环节支持了规则的线下测试、线上调试、灰度发布等功能,监控环节则是支持字段、规则、任务等不一样粒度的异常监控,并支持了规则流量的波动报警、任务的资源报警等功能。

规则引擎的应用解决了数据流ETL链路如何快速响应业务需求的问题,实现了动态调整ETL规则不须要修改代码、重启任务。

但规则引擎自己的迭代、流量增加致使的资源扩容等场景仍是须要升级重启Flink任务,引起断流。除了重启断流外,大任务还可能遇到启动慢、队列资源不足或资源碎片致使起不来等问题。

深度介绍Flink在字节跳动数据流的实践_flink_05


二、Flink拆分任务的实践

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

深度介绍Flink在字节跳动数据流的实践_数据_06

举个例子,上游Topic有200个Partition,咱们在大数据研发治理套件DataLeap的数据开发上配置一个Flink拆分任务只须要指定每一个子任务的流量比例,其他参数均可以按比例自动同步。

拆分任务的应用使得数据流Flink ETL Job除了规则粒度的灰度发布能力,还具有了Job粒度的灰度发布能力,今后升级、扩容不断流,上线风险更可控。同时,因为拆分任务各子任务是独立的,所以单个子任务出现反压、fail-over不会影响其余子任务,对下游的影响更小。另一个优势是单个子任务资源使用量更小,子任务能够同时在多个队列灵活部署。

在流量迅速增加的阶段,数据流最开始是经过Kafka Connector直接写Kafka。可是因为数据流Flink ETL Job任务处理的流量大,Sink比较多,批量发送的效率不高,Kafka集群写入请求量很大,另外因为每一个Sink一个Client,Client与Kafka集群间创建的链接数不少,而Kafka集群因为Controller性能瓶颈也没法继续扩容。

为了缓解Kafka集群压力,数据流Flink ETL Job引入了DataBus组件。

DataBus以Agent的方式 B部署Yarn节点上,Agent中每一个Channel对应一个Kafka Topic。数据流FlinkETL Job每一个TM中的SinkManager使用Databus Client 经过 Unix Domain Socket的方式将数据发送到Databus Agent 的Channel中,再由Channel将数据批量发送到对应的Kafka Topic。

因为每一个Yarn节点上全部的TM都先把数据发送到本机的DataBus Agent,每一个DataBus channel聚合了机器上全部TM Sink写同一个Topic的数据,所以批量发送的效率很是高,极大的下降了Kafka集群的写入请求量,与Kafka集群之间须要创建的链接也更少。

同时,单个请求中数据条数的增长带来更高的压缩效率,在DataBus Agent 上开启了ZSTD压缩后,Kafka集群写入带宽下降了37%,极大的缓解了Kafka集群的压力。

深度介绍Flink在字节跳动数据流的实践_数据_07深度介绍Flink在字节跳动数据流的实践_数据_08

春晚活动是万众瞩目的一大盛事,2021年春晚活动期间数据流对相关的埋点链路进行了重点保障。

首先是完成了多机房的容灾部署并准备了多种切流预案,正常状况下流量会均匀的打到多个机房,MQ多机房同步,Flink ETL Job都从本地消费。若是某个机房出现网络或其余大规模故障,能够从客户端将流量调度到其余机房,也能够在CDN侧将流量调度到不一样的机房,数据流Flink ETL 链路能够分钟级进入容灾模式,切换到可用机房。

为了应对口播期间的流量洪峰,咱们还准备了客户端降级策略与服务端降级策略。其中客户端降级策略能够动态的下降必定百分比用户的埋点上报频率,口播期间不上报,口播结束后逐步恢复。

在降级场景下,下游指标计算能够经过消费未降级的活动埋点分流估算总体指标。春节活动链路的顺利保障标志着数据流基于Flink搭建的ETL链路已经能提供较好的稳定性和可用性。

深度介绍Flink在字节跳动数据流的实践_链路_09

02 - 数据流治理实践

数据流比较常见的治理问题包括但不限于如下几个:

  • 第一个是数据流稳定性治理中最多见的一个问题——Yarn单机问题致使Flink任务fail-over、反压、消费能力降低。Yarn单机问题的类型有不少,好比:队列负载不均、单机load高、其余进程致使CPU负载高、硬件故障等等。
  • 第二个问题是Kafka集群负载不均致使Flink任务生产消费受到影响
  • 第三个问题是埋点治理场景中无用埋点、异常埋点消耗大量计算存储资源

针对单机问题,咱们从Flink和Yarn两个层面分别进行了优化,将单机load高致使的延迟减小了80%以上。

  • 首先,Flink层面的优化。

在数据流ETL场景中,为了减小没必要要的网络传输,Partitioner主要采用Rescale Partitioner。而Rescale Partitioner会使用Round-robin的方式发送数据到下游部分Channel中,因为单机问题可能出现个别任务处理能力不足的状况,致使反压,任务出现lag。

实际上数据发到下游任何一个任务都是能够的,最合理的策略应该根据下游任务的处理能力去发送数据

另外一方面,咱们注意到Flink Credit-based Flow Control反压机制中,能够经过Backlog Size判断下游任务的处理负载,那么咱们就能够将Round-robin发送的方式修改成根据Channel的Backlog Size信息选择负载更低的下游Channel发送的方式。

方案上线后队列的负载更加均衡,CPU利用率提高10%。

深度介绍Flink在字节跳动数据流的实践_数据_10


  • 其次,Yarn层面的优化。

第1、队列资源使用独立Label队列,避免高峰期和其余低优任务互相影响;

第2、Yarn节点上的DataNode偶发有带宽打满、CPU使用高的状况,影响节点上数据流Flink ETL 任务的稳定性,经过给DataNode设置网络限速并进行CPU绑核以免DataNode对Flink进程的影响;

第3、Yarn反调度策略。目前字节跳动Flink使用的Yarn GangScheduler调度策略会根据约束条件选择性的获取分配到的Yarn资源,在任务启动时作到比较均衡的放置Container,但因为时间的推移,流量的变化等诸多因素,队列仍是可能会出现负载不均衡的状况。

反调度策略则是为了解决负载不均衡而生的二次调度机制。Yarn会按期检查集群中再也不知足原有约束的Container,并在这些Container所在的节点上筛选出须要从新调度的Container返回给Flink JobManager,Flink会从新调度这些Container

从新调度会按照原有约束尝试申请等量的可用资源,申请成功后进行迁移,申请不成功不作操做。

深度介绍Flink在字节跳动数据流的实践_数据_11

针对Kafka集群优化问题,咱们自研来了存储计算分离的MQ——BMQ,单GB流量成本降低50%。

在数据流这种大流量场景下使用Kafka,常常会遇到broker或者磁盘负载不均衡、磁盘坏掉等状况,进行扩容、机器替换时的运维操做会引发集群Under Replica, 影响读写性能。除此以外,Kafka还有集群规模瓶颈、多机房容灾部署成本高等缺点。

为了优化这些问题,BMQ这款字节跳动自研的存储计算分离的MQ应运而生。

BMQ数据使用HDFS分布式存储,每一个partition被切分为多个segment,每一个segment对应一个HDFS文件,元数据使用kv存储,Proxy和Broker都是无状态的,所以能够支持快速扩缩容,且没有数据拷贝不会影响读写性能。受益于HDFS多机房容灾部署能力,BMQ多机房容灾部署变得比较简单,数据同时写入全部容灾机房成功后才会向client返回成功,数据消费则是在每一个机房本地消费,减小了跨机房带宽,除此以外,因为基于HDFS存储所需的副本数更少,单GB流量成本降低50%

深度介绍Flink在字节跳动数据流的实践_数据_12

针对埋点治理,咱们从全产品开启埋点管控、无用埋点监控&自助下线、埋点分级、风控能力建设四个点入手。

全产品开启埋点管控。全部产品都须要先在流量平台注册埋点元数据才能上报,这是从埋点接入流程进行的治理。

对已上报的埋点,经过埋点血缘,统计出已经没有在使用的埋点,自动通知埋点负责人在平台进行自助下线。埋点注册和埋点下线完成后,都会经过埋点管控服务动态下发相关的配置信息到埋点SDK和数据流Flink ETL任务中,从而保障未注册埋点和无用埋点在上报或ETL环节被丢弃掉。

根据不一样用途对埋点进行分级,从而Dump到HDFS和数仓的时候能够按不一样等级进行分区,不一样等级的分区提供不一样的TTL和就绪时间的保障。

针对异常流量,数据流ETL链路接入了风控系统,对埋点进行实时打标或过滤,防止异常流量形成数据倾斜、数据延迟、统计指标异常等问题。

深度介绍Flink在字节跳动数据流的实践_数据_13

结语

目前,Flink在字节跳动数据流实践中,已经能够作到计算层面的流批一体。接下来,还将计划探索计算和存储的流批一体,同时也会探索云原生架构,实现资源的动态Rescale,提高资源利用率。此外,在一些高优链路保障上探索追求更高的SLA,好比保障端到端Exactly-once语义。

另,文中所介绍现有的能力目前已经过火山引擎大数据研发治理套件DataLeap对外开放。

  • 关联产品

火山引擎大数据研发治理套件DataLeap

一站式数据中台套件,帮助用户快速完成数据集成、开发、运维、治理、资产、安全等全套数据中台建设,帮助数据团队有效的下降工做成本和数据维护成本、挖掘数据价值、为企业决策提供数据支撑。

  • 欢迎关注字节跳动数据平台同名公众号