本文是字节跳动数据平台开发套件团队在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对外开放。
欢送关注字节跳动数据平台同名公众号