乐趣区

关于Flink:Flink-在字节跳动数据流的实践

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

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

数据流解决的次要是埋点日志。埋点,也叫 Event Tracking,是数据和业务之间的桥梁,是数据分析、举荐、经营的基石。

用户在应用 App、小程序、Web 等各种线上利用时产生的行为,次要通过埋点的模式进行采集上报,按不同的起源分为客户端埋点、Web 端埋点、服务端埋点。

不同起源的埋点都通过数据流的日志采集服务接管到 MQ,而后通过一系列的 Flink 实时 ETL 对埋点进行数据标准化、数据荡涤、实时风控反作弊等解决,最终散发到上游,次要的上游包含 ABTest、举荐、行为剖析零碎、实时数仓、离线数仓。

所以,如果用一句话来概括数据流次要业务,其实就是埋点的收集、荡涤、散发。

目前在字节跳动,荡涤和散发环节是基于 Flink 搭建的。

01 – 数据流业务规模

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

02 – 数据流业务挑战

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

第一点,流量大,工作规模大。
援用
第二点,处在所有产品数据链路最上游,上游业务多,ETL 需要变动频繁。
援用
第三点,高 SLA 要求,上游举荐、实时数仓等业务对稳定性和时效性有比拟高的要求。
援用
最初一点,在流量大、业务多、SLA 要求高的状况下,针对流量、老本、SLA 保障等多维度的综合治理也面临挑战。
援用
上面从两个数据流业务场景中介绍一下咱们遇到的业务挑战。

1、UserAction ETL 场景

在 UserAction ETL 场景中,咱们遇到的外围需要是:品种繁多且流量微小的客户端埋点需要和 ETL 规定动静更新的需要。

在字节外部,客户端的埋点品种繁多且流量微小,而举荐关注的只是局部埋点,因而为了晋升上游举荐零碎解决效率,会在数据流配置一些 ETL 规定,对埋点进行过滤,并对字段进行删减、映射、标准化之类的荡涤解决,将埋点打上不同的动作类型标识。

解决之后的埋点个别称之为 UserAction,UserAction 数据会和服务端展示等数据在举荐 Joiner 工作的分钟级窗口中进行拼接 Join,产出 Instance 训练样本。

举个例子:一个客户端的文章点赞埋点形容了用户在一个工夫点对某一篇文章进行了点赞操作,埋点通过数据流日志采集服务进入数据流 ETL 链路,通过 UserAction ETL 解决后实时地进入到举荐 Joiner 工作中拼接生成样本更新举荐模型,从而晋升用户体验。

如果产出 UserAction 数据的 ETL 链路呈现比拟大的提早,那么就不能在窗口内及时实现拼接,可能导致用户体验降落。

因而对于举荐来说,数据流的时效性是一个强需要。

而举荐模型的迭代、产品埋点的变动都可能导致 UserAction 的 ETL 规定的变动。如果 ETL 规定硬编码在代码中,每次批改都须要降级代码并重启 Flink Job,会影响数据流稳定性和数据的时效性。因而,这个场景的另一个需要就是 ETL 规定的动静更新。

2、数据分流场景

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

如果各业务别离应用一个 Flink 工作,生产抖音埋点 Topic,过滤生产各自关注的埋点,须要耗费大量 Yarn 资源,同时会造成 MQ 集群带宽扇出重大,影响 MQ 集群的稳定性。

因而,数据流提供了数据分流服务,应用一个 Flink 工作生产上游埋点 Topic,而后通过配置规定的形式,将各业务关注的埋点分流到上游小 Topic 中,再提供给各个业务生产。这样就缩小了不必要的反序列化开销,同时升高了 MQ 集群带宽扇出比例。

在数据分流场景中,外围须要解决的是高稳固的 SLA。因为断流、数据提早可能会影响举荐成果、广告支出、实时数据报表。

同时随着业务倒退,实时数据需要日益减少,分流规定新增和批改也会日益频繁。如果每次规定变动都须要批改代码并重启 Flink Job,会影响很多上游,因而分流规定的动静更新也是这一场景中的强需要。

字节跳动数据流实际

01- 数据流 ETL 链路建设

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

第一阶段是 2018 年以前业务需要疾速迭代的晚期阶段

次要应用 PyJStorm 和基于 Python 的规定引擎构建次要的流式数据处理链路。其特点是比拟灵便,能够疾速反对业务需要。

但随着埋点流量疾速上涨,PyJStorm 暴露出很多稳定性和运维上的问题,性能也不足以撑持业务的增长。

2018 年,公司外部开始大力推广 Flink,并且针对大量旧工作应用 PyJStorm 的状况,提供了 PyJStorm 到 PyFlink 的兼容适配。流式工作托管平台的建设肯定水平上解决了流式工作运维治理的问题。数据流 ETL 链路也在 2018 年全面迁徙到了 PyFlink,进入了流式计算的新时代。

第二个阶段是 2018 至 2020 年

随着流量的进一步上涨,PyFlink 和 Kafka 的性能瓶颈、以及 JSON 数据格式带来的性能和数据品质问题都一一显现出来,与此同时上游业务对提早、数据品质的敏感水平却是一劳永逸。

于是,咱们一方面对一些痛点进行了针对性的优化。另一方面,破费 1 年多的工夫将整个 ETL 链路从 PyFlink 切换到了 Java Flink,应用基于 Groovy 的规定引擎替换了基于 Python 的规定引擎,应用 ProtoBuf 替换了 JSON。

数据流 ETL 新链路,相比旧链路性能晋升了 1 倍。

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

第三个阶段是从 2021 年开始

在寰球资源供给缓和的背景下,进一步晋升数据流 ETL 性能和稳定性,满足流量增长和需要增长的同时,升高资源老本和运维老本,是这一阶段的次要指标。咱们次要从三个方面进行了优化:

优化引擎性能 。随着流量和 ETL 规定的一直减少,基于 Groovy 的规定引擎应用的资源也一直减少,于是咱们基于 Janino 进行了重构,引擎性能失去数倍晋升。
优化埋点治理体系 。咱们基于流量平台建设了一套比较完善的埋点治理体系,通过无用埋点下线、埋点采样等伎俩升高埋点老本。
优化链路。咱们进行了链路分级,不同等级的链路保障不同的 SLA,在资源有余的状况下优先保障高优埋点链路。

从 2018 年到 2020 年,咱们继续在数据流 Flink ETL Job 应答需要挑战上获得了一些实际成果。下图展现了数据流 Flink ETL Job 是如何反对动静更新的,在不重启工作的状况下,实时更新上下游 Schema、规定解决逻辑、批改路由拓扑。

流量平台 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 中。

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

这里解释一下咱们为什么让每个 TaskManager 通过一个 MetaData updater 定时去更新元数据,而不是通过减少一条元数据流来更新。这么做的起因次要是因为应用元数据流更新的形式须要开启 Checkpoint 以保留元数据的状态,而在字节跳动数据流这样的大流量场景下,开启 Checkpoint 会导致在 Failover 时产生大量反复数据,上游无奈承受。

1、规定引擎的解决方案

数据流 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 工作,引发断流。除了重启断流外,大工作还可能遇到启动慢、队列资源有余或资源碎片导致起不来等问题。

2、Flink 拆分工作的实际

针对这些痛点,咱们上线了 Flink 拆分工作。Flink 拆分工作实质上就是将一个大工作拆分为一组子工作,每个子工作按比例生产上游 Topic 一部分 Partition,解决后再别离写出到上游 Topic。

举个例子,上游 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 的形式部署 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 集群的压力。

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

首先是实现了多机房的容灾部署并筹备了多种切流预案,失常状况下流量会平均的打到多个机房,MQ 多机房同步,Flink ETL Job 都从本地生产。如果某个机房呈现网络或其余大规模故障,能够从客户端将流量调度到其余机房,也能够在 CDN 侧将流量调度到不同的机房,数据流 Flink ETL 链路能够分钟级进入容灾模式,切换到可用机房。

为了应对口播期间的流量洪峰,咱们还筹备了客户端降级策略与服务端降级策略。其中客户端降级策略能够动静的升高肯定百分比用户的埋点上报频率,口播期间不上报,口播完结后逐渐复原。

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

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%。

其次,Yarn 层面的优化。

第一、队列资源应用独立 Label 队列,防止高峰期和其余低优工作相互影响;

第二、Yarn 节点上的 DataNode 偶发有带宽打满、CPU 应用高的状况,影响节点上数据流 Flink ETL 工作的稳定性,通过给 DataNode 设置网络限速并进行 CPU 绑核以防止 DataNode 对 Flink 过程的影响;

第三、Yarn 反调度策略。目前字节跳动 Flink 应用的 Yarn GangScheduler 调度策略会依据约束条件选择性的获取调配到的 Yarn 资源,在工作启动时做到比拟平衡的搁置 Container,但因为工夫的推移,流量的变动等诸多因素,队列还是可能会呈现负载不平衡的状况。

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

从新调度会依照原有束缚尝试申请等量的可用资源,申请胜利后进行迁徙,申请不胜利不做操作。

针对 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%。

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

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

第二点,对于已上报的埋点,咱们会通过埋点血统,统计出曾经没有在应用的埋点,主动告诉埋点负责人在平台进行自助下线。埋点注册和埋点下线实现后,都会通过埋点管控服务动静下发相干的配置信息到埋点 SDK 和数据流 Flink ETL 工作中,从而保障未注册埋点和无用埋点在上报或 ETL 环节被抛弃掉。

第三点是依据不同的用处对埋点进行分级,从而 Dump 到 HDFS 和数仓的时候能够按不同等级进行分区,不同等级的分区提供不同的 TTL 和就绪工夫的保障。

最初一点则是针对异样流量,数据流 ETL 链路接入了风控系统,对埋点进行实时打标或过滤,避免异样流量造成数据歪斜、数据提早、统计指标异样等问题。

目前,Flink 在字节跳动数据流实际中,曾经能够做到计算层面的流批一体。接下来,咱们还将打算摸索计算和存储的流批一体,同时也会摸索云原生架构,实现资源的动静 Rescale,晋升资源利用率。咱们也会一些高优链路保障上谋求更高的 SLA,比方保障端到端 Exactly-once 语义。

目前,现有的能力曾经通过火山引擎大数据研发治理套件 DataLeap 对外开放。

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

退出移动版