动手点关注
干货不迷路
随着字节跳动旗下业务的快速发展,数据急剧膨胀,原有的大数据架构在面临日趋复杂的业务需求时逐渐显现疲态。而伴随着大数据架构向云原生演进的行业趋势,字节跳动也对大数据体系进行了云原生改造。本文将详细介绍字节跳动大数据容器化的演进与实践。
从2017年起,字节跳动陆续推出多款广为人知的热门应用,如抖音、今日头条、西瓜视频、剪映、番茄小说、懂车帝等。随着行业的快速发展和业务的高速迭代,数据量也呈爆炸式增长,海量的数据规模、愈加复杂的场景使得各大业务对字节底层大数据运算能力的要求不断提高。以抖音的实时推荐为例。系统需要从亿万级别的内容库中选出用户可能感兴趣的内容,运用复杂的模型对内容进行打分排序,再通过广告系统的处理,最后呈现给用户,整个过程需要在300毫秒内完成。这就对背后的计算能力提出了很高的要求,只有庞大的计算资源和极致的性能优化,才能达到这一业务需求。目前字节跳动的大数据集群已经支持了 EB 级的海量存储空间和千万级 Core 的计算资源调度能力。
传统大数据组件繁多,安装运维复杂,在生产使用中需要大量的人力支持,不仅集群搭建费时费力,还容易形成运维孤岛和数据孤岛现象。同时在资源利用、可观测性等方面也存在诸多不足,已经越来越无法适应当下的发展需求。在此情况下,业界逐渐开始往云原生大数据方案发展。
云原生大数据是大数据平台新一代架构和运行形态,是一种以平台云原生化部署、计算云原生调度、存储统一负载为特点,可以支持多种计算负载,计算调度更弹性,存储效能更高的大数据处理和分析平台。云原生大数据带来了大数据在使用和运维方面的巨大变化,从以下两个角度来看:
业务层面:传统模式下,业务独立占用资源,在低谷时段资源占用率可能只有20%-30%;云原生模式下的业务是混部的,比如在线和离线业务,它可以按分时复用的方式来调用资源,以此来提高集群利用率。
运维层面:传统的大数据架构通常是基于物理硬件的,每个集群都需要单独管理,扩展和升级非常困难。当需要增加更多的节点或更改硬件配置时,需要进行繁琐的人工操作,而且很容易出现错误。云原生模式将平台组件容器化后,可以利用弹性伸缩、自动化管理等特性,可以更好的进行集群的运维工作。
目前,新一代的字节跳动大数据平台已全面拥抱云原生,支持“三大平台和一大支撑体系”的功能架构:
平台服务层:由开源组件插件化集成,支持灵活配置选用;
核心引擎层:包括 Flink、Spark、云原生消息引擎、实时服务分析引擎、云原生日志搜索和统一存储 HDFS 等核心组件,支持存算分离和自动调优;
资源调度层:支持统一计算资源调度和统一引擎云原生生命周期管理。
运维管理平台 : 是集开源组件、服务生命周期、集群、容灾、可观测性于一体的一站式管理平台。
比较幸运的是,开源的大数据组件大部分将容器化基本做好了,如开源的 HDFS 其实已经可以直接基于 K8s 进行部署,像 Flink/Spark 这样的计算引擎也早就支持了 on K8s 部署和运行。因此在大数据业务容器化的过程中,我们要解决的问题是如何更好地运行和管理这些大数据任务。由此延伸,在此过程中会遇到以下几个主要问题:
容器化平台不具备与 YARN 队列类似的资源管控能力;
调度器吞吐能力差,不适用于任务量大且运行时间较短的大数据作业;
调度器不存在“作业”概念,不具备作业排队能力,不具备作业级调度策略;
原生的大数据作业在容器化提交后,往往状态信息获取不准确;
大数据作业容器化部署后导致日志收集、监控告警变得复杂。
为了解决以上问题,字节跳动云原生大数据平台引入大数据作业调度器 GRO 封装 YARN 队列,提升大数据作业吞吐能力,并抽象作业支持企业级调度;引入云原生大数据 Operator Arcee,用于解决状态信息获取不准确的问题;构建统一运维平台,支持统一监控/日志等能力。以下我们将对这三部分进行展开介绍。
在大数据作业中,特别是批式计算的作业通常只会占用资源一段时间,在运行结束后即归还资源。而用户通常会提交多个作业,这就导致部分作业不能立即获得资源,而需要排队等待直到有作业结束退出后才能获得资源开始运行。但原生 Kubernetes 调度器最初是针对在线服务设计的,没有“队列”和“作业”这两个概念。为了更好地支持大数据场景资源分配,我们自研了高性能资源管理调度器 GRO,用于管控集群资源,并且新增了以下两个重要概念:
Queue CRD:描述了一个“队列”,即 Quota(资源配额)的抽象;
PodGroup CRD:描述了一个“作业”,用于标识多个 Pod 属于同一个集合,从而可以把多个 Pod 看作整体进行调度。
GRO 组件给容器化平台带来了如弹性队列、调度策略、Quota 管控等新的特性 。
每个队列可以设置两个资源配额属性:
Min Quota,又称为保障资源量。调度器为该队列预留 Min Quota 的资源量,不允许其他队列占用,以保障该队列在需要使用时可以立刻获得资源;
Max Quota,又称为资源使用上限。调度器限制该队列使用资源不超过 Max Quota 的资源量。
GRO 将根据所有队列的 Min-Max 属性,将集群资源公平地分配给各个队列,再根据不同的调度策略,将队列资源公平地分配给队列内的各个作业,再进一步分配给不同作业内的各个 Pod。
在具备了队列和作业两个概念后,还可以支持以下常用的调度策略:
优先级调度:所有作业按照定义的优先级排序,调度器优先分配高优先级的作业;
Gang 调度:调度器一次性为作业的所有 Pod 分配资源,或者一个 Pod 也不分配,保证不出现一个作业的部分 Pod 启动,部分 Pod 排队等待的情况;一个作业只有部分 Pod 启动,有可能不能正常运行,这样不仅浪费了集群资源,还可能存在多个类似作业相互死锁,导致所有作业都不能正常运行;
DRF 调度:调度器公平分配资源给各个作业的同时,兼顾多维度资源的比例,尽可能提升资源利用率;比如队列剩余大量 CPU 和少量内存时,优先分配 CPU 需求多、内存需求少的作业,避免队列的内存完全耗尽,大量 CPU 剩余,无法被利用的问题。
GRO 也可以支持其他 Quota 管控策略:
队列间抢占:队列没有使用的 Quota 允许临时被其他队列占用,当队列有资源需求时,可以从其他队列将资源抢占回来;
队列内抢占:队列没有剩余 Quota,高优作业提交后可以将正在运行的低优作业占用的资源抢占回来;
大作业资源预留:资源需求较大的作业很有可能因为节点资源碎片而一直无法调度,通过调度器支持预留节点资源,可以保证大作业调度成功。
为解决“原生的大数据作业在容器化提交后,往往状态信息获取不准确”的这个问题,我们通过自研的 Arcee Operator 作为大数据统一的 Operator ,从而实现统一管控多种计算引擎。
Arcee 借鉴了 YARN 的两级管理模式,管理大数据作业的 Application Master,再由 AM 管理计算 Worker。AM 包括 Flink JobManager、Spark Driver 等,负责计算 Worker 的启动、删除、运行状态采集及心跳检测,横向扩缩容等工作。并且由 Arcee 负责 AM Pod 的启动、失败重启、结束删除、运行状态采集等整个生命周期管理。
在引入 Arcee 之后,给我们带来了如下关键特性:
定义了统一的 Application: Arcee Application 通过相同的方式表达 Flink、Spark 等作业的配置、规格等描述,并且使用相同的状态机,结合调度和引擎信息呈现准确、详细的作业状态。不同计算引擎的统一描述和状态有利于业务上的统一表达和处理。
Arcee 实现了作业异常处理 : Arcee 实时监控所有 AM 状态,具有丰富的异常处理策略,包括 AM 重启、Worker 清理等,持续保障作业正常运行。
Arcee 屏蔽了底层调度器 : 作业通过 Arcee 可以轻松使用底层调度器支持的队列调度、优先级调度、Gang 调度等多种调度策略。同时 Arcee 也可以采集并展示作业的调度信息。Arcee 降低了高级调度功能的接入门槛。
完整支持计算框架各种运行模式。例如:Flink Session Mode & Flink Application Mode、Spark Client Mode & Spark Cluster Mode。
在具备 GRO 和 Arcee 之后,一个大数据任务已经可以容器化运行在我们的新一代大数据平台之上了。那么接下来要面临的就是如何运维,这其中的关键可以感知到该作业的监控和日志信息。
服务监控指标的采集分为两种:
常驻服务的监控数据:常驻服务集成了 Prometheus 的采集器,Prometheus 会做 Pod 服务的自动发现,并会周期性的同步这些服务的监控数据。
Flink 任务的监控数据:由 Flink 程序主动 Push 监控数据到 Push-gateway 中,然后 Prometheus 可以周期性的同步 push-gateway 中的数据。
数据面支持多套计算集群,不同的计算集群都部署了一套 Prometheus ,从而使不同集群的 Prometheus 在采集到监控指标之后,用 Remote Write 的方式将监控指标数据写入到控制面的 Storeage 上,这里的 Storage 是一个抽象的接口,可以支持火山引擎的云监控存储、S3 存储、CloudFS 存储及其他的自定义存储等。
日志的来源分为两种,一种是直接将服务的日志写入本地文件,然后通过 Filebeat 收集路径文件并推送到 LogProxy 上;另一种是作业通过集成 Collector 将日志远程写入到 LogProxy 上。
Log Proxy 是日志的一个代理服务,内置在每个 K8s 集群中,负责该集群内所有日志数据的汇聚、整理及写入到 Kafka 上的工作。Kafka 在这里可以完成日志转存的操作,用于避免短时间内大流量的日志信息将下游的日志存储服务打爆。同时考虑到日志服务本身的监控和运维能力,我们在 Kafka 侧也暴露了一些指标用于监控 Kafka 上日志消息堆积的情况。同时在 Kafak 往下游写数据的过程中还额外做了动态限流的相关工作,通过自动感知到下游服务的吞吐量来进行流量的动态调整,在保证稳定性的同时,尽可能的将日志文件快速写入到下游平台上。
日志数据写入到日志存储服务后,为了方便用户通过页面或者接口的方式进行日志查看,我们也研发了一个独立的、对外提供统一的日志搜索 API 模块。无论是前端用户还是 OpenAPI 用户都可以使用该服务的 API 进行相关大数据作业日志的搜索事宜。
基于原生大数据组件自身的容器化能力,以及 GRO、Acree、监控、日志这几个平台级别的优化,平台可以基本达到完全容器化的状态。以某头部证券客户的大数据作业容器化实践为案例,客户希望基于云原生构建业务敏捷和运维便捷的基础设施。结合大数据云原生化已被作为企业的重要战略方向,实现流式计算 Flink 的云原生化是其中的一个重要里程碑。
多环境管理
基于银监会的政策性指导文件,我们需要进行多环境的管理,支持生产和测试双集群的能力。如下架构图所示,在测试集群和生产集群分别部署了一套平台,每个平台都有自己独立的入口,具备完全相同的业务能力。为了平台的易用性,通过新增一个辅助服务的组件,可以用来处理产品同步、上线审批、任务同步等操作。
在此类业务场景中,容器化带来的最大收益就是相较于传统大数据平台,容器化后的大数据作业,可移植性更强,真正实现了一次编写、多处运行。减少或避免了在传统大数据平台场景下,测试环境完成的研发工作上线到线上环境后出现的 Jar 冲突或者其他环境问题。
跨数据中心高可用
除了对生产测试的多环境管理刚需之外,金融行业普遍对跨数据中心的高可用也非常关注。
在大数据场景中,跨机房高可用的实现需要从以下三个维度综合考虑,分别是:服务的高可用、数据的高可用、作业的高可用。
服务高可用:业内已经有非常成熟的方案了,因此在本篇中不再过多赘述。
数据高可用:通过依靠字节跳动大数据文件存储系统 CloudFS 实现的,和 HDFS 架构基本类型,具备 NN 和 DN 组件,在容灾场景下 CloudFS 可以横跨数据中心进行部署,在不同的集群上部署 NN 和 DN 组件,当写入一个文件块的时候,会同步写入到多个数据中心的集群上,以保障数据的高可用性。
作业高可用:通过引入 Reslake 组件,帮助平台屏蔽底层的计算资源,该组件具有资源的全局视图,拥有全局资源池 Quota 管控,可以不限机房、不限集群、以最优化资源利用率为最终的调度目标。于此同时还具备对数据中心、机房、集群的存活状态自动感知的特性,当发现其中某个节点出现停机故障时会进行任务的迁移,将相关的任务迁移到其他可用的集群、机房或数据中心,以达到作业的高可用性。
在这个场景下,容器化带来的最大收益就是相较于传统大数据平台,容器化后的大数据平台可运维性更强,可以做到无需额外操作即可自动恢复的能力,真正做到省心,省力。
在前文中,我们对云原生大数据平台实践进行了一些探讨。在6月10日上海,来自字节跳动云原生大数据的技术专家们将在此基础之上,进一步带来包括 Flink、RAY、Elasticsearch 项目等大数据主流数据计算基础设施在云原生场景下的实践与解析。欢迎一键报名~
点击「阅读原文」 了解更多活动详情 !