揭秘字节跳动云原生sparkhistory服务uiservice

字节跳动数据平台      2022-03-19     244

关键词:

本文是字节跳动数据平台数据引擎SparkSQL团队针对 Spark History Server (SHS) 的优化实践分享。

揭秘字节跳动云原生Spark

*文 | 字节跳动数据平台—数据引擎—SparkSQL团队*

在字节跳动内部,我们实现了一套全新的云原生 Spark History 服务—— UIService,相比开源的 SHS,UIService 存储占用和访问延迟均降低 90% 以上,目前 UIService 服务已经在字节跳动内部广泛使用,并且作为火山引擎湖仓一体分析服务 LAS(LakeHouse Analytics Service)的默认服务。

LAS

业务背景

开源 Spark History Server 架构

为了能够更好理解本次重构的背景和意义,首先对原生 Spark History Server 原理做个简单的介绍。

揭秘字节跳动云原生Spark

开源 Spark History Server 流程图

Spark History 建立在 Spark 事件(Spark Event)体系之上。在 Spark 任务运行期间会产生大量包含运行信息的SparkListenerEvent,例如 ApplicationStart / StageCompleted / MetricsUpdate 等等,都有对应的 SparkListenerEvent 实现。所有的 event 会发送到ListenerBus中,被注册在ListenerBus中的所有listener监听。其中EventLoggingListener是专门用于生成 event log 的监听器。它会将 event 序列化为 Json 格式的 event log 文件,写到文件系统中(如 HDFS)。通常一个机房的任务的文件都存储在一个路径下。

在 History Server 侧,核心逻辑在 FsHistoryProvider中。FsHistoryProvider 会维持一个线程间歇扫描配置好的 event log 存储路径,遍历其中的 event log 文件,提取其中概要信息(主要是 appliaction_id, user, status, start_time, end_time, event_log_path),维护一个列表。当用户访问 UI,会从列表中查找请求所需的任务,如果存在,就完整读取对应的 event log 文件,进行解析。解析的过程就是一个回放过程(replay)。Event log 文件中的每一行是一个序列化的 event,将它们逐行反序列化,并使用 ReplayListener将其中信息反馈到 KVStore 中,还原任务的状态。

无论运行时还是 History Server,任务状态都存储在有限几个类的实例中,而它们则存储在 KVStore中,KVStore是 Spark 中基于内存的KV存储,可以存储任意的类实例。前端会从KVStore查询所需的对象,实现页面的渲染。

痛点

存储空间开销大

Spark 的事件体系非常详细,导致 event log 记录的事件数量非常大,对于UI显示来说,大部分 event 是无用的。并且 event log 一般使用 json 明文存储,空间占用较大。对于比较复杂或时间长的任务,event log 可以达到几十GB。字节内部7天的 event log 占用约 3.2 PB 的 HDFS 存储空间。

回放效率差,延迟高

History Server 采用回放解析 event log 的方式还原 Spark UI,有大量的计算开销,当任务较大就会有明显的响应延迟,响应延迟是指从用户发起前端访问到页面 UI 完全渲染出来的等待时长。作业结束之后,用户可能要等十几分钟甚至半小时才能通过 History Server 看到作业历史。而大型作业结束后,用户往往希望尽快看到作业历史从而根据作业历史进行问题诊断和作业优化,用户等待 UI 完成渲染时间过长,非常影响用户体验。

扩展性差

如上所述,History Server 的FsHistoryProvider在回放解析文件之前,需要先扫描配置的 event log 路径,遍历其中的 event log,将所有文件的元信息加载到内存中,这使得原生服务成为了有状态的服务。因此每次服务重启,都需要重新加载整个路径,才能对外服务。每个任务在完成后,也需要等待下一轮扫描才能被访问到。

当集群任务数量增多,每一轮扫描文件的耗时以及元信息内存占用都会增加,这也要求服务有越来越高的资源配置。如果通过拆分 event log 路径来缩小单实例的压力,需要对路由规则进行改造,运维难度增大。目前,字节跳动内部通过增加 UIService 实例就可以方便的进行水平扩展。

非云原生

Spark History Server 并非是云原生的服务,在公有云场景下改造和维护成本高。首先公有云场景需要进行租户资源隔离,其次公有云场景下不同用户的 workload 差异很大,不同用户任务量有数量级的差别,会出现大量长尾作业。为每个用户单独部署 History Server 计算和存储成本过大且不均衡,而部署统一的 History Server 无法做到资源隔离,一旦出现问题影响较多用户,两种方式运维成本都会很高。火山引擎湖仓一体分析引擎 LAS(Lakehouse Analytics Service),提供了云原生的 UIService,可以有效解决上述问题。

UIService

方案

为了解决前面的三个问题,我们尝试对 History Server 进行改造。

如上所述,无论运行中的 Spark Driver 还是 History Server,都是通过监听 event,将其中包含的任务变化信息反映到几种 UI 相关的类的实例中,然后存入KVStore供 UI 渲染。也就是说,KVStore中存储着 UI 显示所需的完备信息。对于 History Server 的用户来说,绝大多数情况下我们只关心任务的最终状态,而无需关心引起状态变化的具体 event。

因此,我们可以只将 KVStore 持久化下来,而不需要存储大量冗余的 event 信息。此外,KVStore原生支持了 Kryo 序列化,性能明显于 Json 序列化。我们基于此思想重写了一套新的 History Server 系统,命名为 UIService。

揭秘字节跳动云原生Spark

UIService框架图

实现

UIMetaStore

KVStore中和 UI 相关的所有类实例,我们将这些类统称为 UIMeta 类。具体包括 AppStatusStore和SQLAppStatusStore中的信息(如下所列)。我们定义一个类 UIMetaStore来抽象,一个UIMetaStore即一个任务所有 UI 信息的集合。

UIMetaStore所包含信息:

# AppStatusStore
org.apache.spark.status.JobDataWrapper
org.apache.spark.status.ExecutorStageSummaryWrapper
org.apache.spark.status.ApplicationInfoWrapper
org.apache.spark.status.PoolData
org.apache.spark.status.ExecutorSummaryWrapper
org.apache.spark.status.StageDataWrapper
org.apache.spark.status.AppSummary
org.apache.spark.status.RDDOperationGraphWrapper
org.apache.spark.status.TaskDataWrapper
org.apache.spark.status.ApplicationEnvironmentInfoWrapper

# SQLAppStatusStore
org.apache.spark.sql.execution.ui.SQLExecutionUIData
org.apache.spark.sql.execution.ui.SparkPlanGraphWrapper

UIMetaStore 还定义了持久化文件的数据结构,结构如下:

4-Byte Magic Number: "UI_S"
----------- Body ---------------
4_byte_length_of_class_name | class_name_str1 | 4_byte_length | serialized_of_class1_instance1
4_byte_length_of_class_name | class_name_str1 | 4_byte_length | serialized_of_class1_instance2
4_byte_length_of_class_name | class_name_str2 | 4_byte_length | serialized_of_class2_instance1
4_byte_length_of_class_name | class_name_str2 | 4_byte_length | serialized_of_class2_instance2
  • Magic Number用于文件类型标识校验。
  • Body 是 UIMetaStore 的主体数据,使用连续存储。每一个 UI 相关的类实例,会序列化成四个片段:类名长度(4 byte long 类型)+ 类名(string 类型)+ 数据长度(4 byte long 类型)+ 序列化的数据(二进制类型)。在读取时顺序读取,每个元素先读取长度信息,再根据长度读取后续相应数据进行反序列化。
  • 使用 Spark 原生的KVStoreSerializer序列化,可以保证前后兼容性。

UIMetaLoggingListener

类似于EventLoggingListener,为 UIMeta 开发了专用的 Listener —— UIMetaLoggingListener,用于监听事件,写 UIMeta 文件。

和EventLoggingListener进行对比:EventLoggingListener每接受一个 event 都会触发写,写的是序列化的 event;而UIMetaLoggingListener只会被特定的 event 触发,目前是只会被stageEnd,JobEnd 事件触发,但每次写操作是批量的写,将上一阶段的UIMetaStore的信息完整地持久化。

做一个类比,EventLoggingListener好比流式,不断地追加写,而 UIMetaLoggingListener类似于批式,定期将任务状态快照下来。

UIMetaProvider

替换原先的FsHistoryProvider,主要区别在于:

将读取 event log 文件和回放生成KVStore的流程改为读取UIMetaFile,反序列化出UIMetaStore。

去掉了FsHistoryProvider的路径扫描逻辑;每次 UI 访问,根据 appid 和路径规则,直接去读取 UIMetaFile 解析。这使得 UIService 无需预加载所有文件元信息,不需要随着任务数量增加提高服务器配置,方便了水平扩展。

优化

避免重复写

由于每个 stage 完成都会触发写 UIMeta 文件,这样对于 UIMeta 的很多元素,可能会出现重复持久化的情况,增加写入耗时和文件的大小。因此我们在UIMetaLoggingListener内部维护了一个 map,记录已经被序列化的实例。在写 UIMeta 文件时进行过滤,只写没有写过或者数据发生改变的元素。这样可以杜绝大部分的写冗余。

此外,开发期间发现,占用空间最大的是task级别信息TaskDataWrapper。在一个 stage 完成触发写时。可能会将仍处于 RUNNING 状态的 stage 的 task 序列化下来,这样当 RUNNING 的 stage 完成时,task 信息会再被写一次,也会造成数据冗余,因此我们对序列化TaskDataWrapper信息进行过滤,在 stage 结束时只持久化状态是 Completed 的 task 信息。

支持回退到 event log

鉴于 UIService 在初期有存在问题的风险,我们还支持了回退机制,即访问一个任务的 UI,优先尝试走 UIService 的路径:解析 UIMeta 文件,如果 UIMeta 文件不存在或者解析报错,会回退到读 event log 文件的路径,避免 UI 访问失败。同时还支持将 event log 文件转换成 UIMeta 文件,这样下一次调用时就可以使用 UIService。这个功能保证我们迁移过程的平滑。

收益

存储收益

线上测试显示存储平均减少85%,总量减少92.4%。

下图显示了某机房 event log 和 UIMeta 存储占用监控,可以看到 UIMeta 较 event log 在存储量上有数量级的减少。目前字节内部7天的 event log 占用存储空间 3.2 PB,改用 UIMeta 后,空间占用只有350TB。

凭借 UIService 的存储优势,我们可以保留更长时间的日志信息,有助于历史分析,问题复盘。目前我们已从保留7天日志提高到了保留30天,并可以根据需求增大保留时间。

揭秘字节跳动云原生Spark

某机房 event log/UIMeta HDFS存储监控对比

访问延迟收益

访问延迟:平均缩短 35%,PCT90/95/99 分别减少 84.6%/90.8%/93.7%

揭秘字节跳动云原生Spark

访问延迟百分位分布

如下图所示,UIService 的 UI 访问延迟整体较比 event log 向左移,长尾任务明显减少。

揭秘字节跳动云原生Spark

访问延迟分布图

架构收益

去掉了原生 History Server 遍历路径,预加载的耗时环节,消除从任务完成到 History Server 可访问的时间间隔,从原本的平均 10min 左右降低到秒级,任务完成即可立即对外提供服务。同时使 History Server 可以水平扩展,能更好应对未来任务量增长带来的挑战。

目前,字节跳动内部我们通过增加 UIService 实例就可以方便的进行横向扩展。在火山引擎湖仓一体分析服务 LAS 中,我们也基于 UIService 实现了支持租户访问隔离,云原生的,可按需伸缩的 Spark History Server。

​点击了解火山引擎湖仓一体分析服务LAS​

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

字节跳动c++云原生二面(65min)(代码片段)

字节跳动C++云原生二面(65min)面试问题HTTP1.0、1.1和2.0的区别和差异是什么《HTTP1.0和1.1的区别》HTTP1.1默认开启长连接(keep-alive)而HTTP1.0需要添加参数,在一定程度上减少了建立和关闭连接的消耗和延... 查看详情

字节跳动c++云原生二面(65min)(代码片段)

字节跳动C++云原生二面(65min)面试问题HTTP1.0、1.1和2.0的区别和差异是什么《HTTP1.0和1.1的区别》HTTP1.1默认开启长连接(keep-alive)而HTTP1.0需要添加参数,在一定程度上减少了建立和关闭连接的消耗和延... 查看详情

火山引擎进军云市场,计划未来三年服务十万客户

12月2日,火山引擎在升级为字节跳动企业级技术服务业务板块之后,首次亮相就正式发布全系云产品,包括云基础、视频及内容分发、数据中台、开发中台、人工智能等五大类、共计78项服务。火山引擎云产品是字节... 查看详情

火山引擎项亮揭秘字节跳动基于hpc的大规模机器学习技术|直播分享报名

机器学习是当前领先的AI范式,到目前为止取得了非常可观的成就,当前机器学习也是一个非常时髦的话题。2021年12月火山引擎云产品发布会上正式发布了 AI全系产品,其中的AI开发平台就是全流程、高效率、高性能... 查看详情

字节跳动数据库的过去现状与未来

一文概述字节跳动云原生数据库系统的发展作者| 张雷(字节跳动-基础架构-数据库资深研发工程师)数据库技术一直是信息技术中极其重要的一环,在步入云原生时代后,云基础设施和数据库进一步整合,弥... 查看详情

火山引擎dataleap:揭秘字节跳动数据血缘架构演进之路

更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群DataLeap是火山引擎数智平台VeDI旗下的大数据研发治理套件产品,帮助用户快速完成数据集成、开发、运维、治理、资产、安全等全套... 查看详情

内含福利|csdn携手字节跳动:云原生meetup北京站报名热烈启动,1月8日见!

...发者和企业有效解决业务问题。2022年1月8日,CSDN携手字节跳动基础架构,将在北京举办第四场云原生线下Meetup。在这里,您可以与众多开源技术专家现场对话,了解开源服务框架一线信息,洞悉技术发展的先... 查看详情

内含福利|csdn携手字节跳动:云原生meetup北京站报名热烈启动,1月8日见!

...发者和企业有效解决业务问题。2022年1月8日,CSDN携手字节跳动基础架构,将在北京举办第四场云原生线下Meetup。在这里,您可以与众多开源技术专家现场对话,了解开源服务框架一线信息,洞悉技术发展的先... 查看详情

免费活动字节跳动背后的音视频技术揭秘

音视频技术在近几年呈现突飞猛进的发展,一方面满足了企业对于业务高速增长的需求,另一方面也为业务的发展创造了更多的可能性。活动介绍10月29日|北京LiveVideoStack将联合火山引擎的5位技术专家在本专题中,展... 查看详情

为什么华为阿里字节跳动微软等都走上了云原生和数字化之路?

亲爱的开发者朋友们好哇,前几天我发了篇文章,请各位朋友帮忙给最新一期的《新程序员》选封面,并且和大家说内容已经全部完成,即将出版和大家正式见面。今天,它来啦!《新程序员003:云原... 查看详情

为什么华为阿里字节跳动微软等都走上了云原生和数字化之路?

亲爱的开发者朋友们好哇,前几天我发了篇文章,请各位朋友帮忙给最新一期的《新程序员》选封面,并且和大家说内容已经全部完成,即将出版和大家正式见面。今天,它来啦!《新程序员003:云原... 查看详情

字节跳动背后的音视频技术揭秘

在过去的一年中,我们可以看到多媒体特别是音视频技术的能力在严峻的挑战下,为各行各业带来了巨大的变化。疫情过后,又会有哪些多媒体新技术、新实践呈现在大众的视野当中?为行业的发展与应用带来哪... 查看详情

揭秘字节跳动埋点数据实时动态处理引擎(附源码)(代码片段)

1.序篇-先说结论宝贝们,还记得前几天博主去的火山引擎大数据场嘛,其中比较令大家感兴趣的就是最后一讲,字节一站式埋点平台的flink标准化清洗及拆流任务。其中大家感觉比较流啤的就是的就是字节做到了:... 查看详情

字节跳动双11电商直播技术大揭秘

...团队中负责直播客户端SDK团队的徐鸿,请他来给大家揭秘双11抖音电商直播背后的技术实践,同时徐鸿也分享了他对音视频技术未来发展趋势的看法。字节跳动技术访谈#010#LiveVideoStack:徐老师,请问您目前在字节跳动... 查看详情

揭秘传统数据库转型云原生的迅猛趋势

文章目录前言一、传统数据库的三大痛点二、云原生数据库是什么三、云原生数据库的优点四、云原生数据库技术特性1.无处不在的存算分离2.提升效能的分布式五、AmazonAurora云原生数据库1.首个云原生数据库存算分离技术实践2.... 查看详情

apachepulsar在火山引擎emr的集成与场景(代码片段)

更多技术交流、求职机会,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群 近年来,基于云原生架构的新一代消息队列和流处理引擎ApachePulsar在大数据领域发挥着愈发重要的作用,其应用场景和客户案例... 查看详情

为什么华为阿里字节跳动微软等都走上了云原生和数字化之路?

亲爱的开发者朋友们好哇,前几天我发了篇文章,请各位朋友帮忙给最新一期的《新程序员》选封面,并且和大家说内容已经全部完成,即将出版和大家正式见面。今天,它来啦!《新程序员003:云原... 查看详情

为什么华为阿里字节跳动微软等都走上了云原生和数字化之路?

亲爱的开发者朋友们好哇,前几天我发了篇文章,请各位朋友帮忙给最新一期的《新程序员》选封面,并且和大家说内容已经全部完成,即将出版和大家正式见面。今天,它来啦!《新程序员003:云原... 查看详情