从混合部署到融合调度:字节跳动容器调度技术演进之路

技术

picture.image

作者 | 字节跳动基础架构

字节服 务体系大致分为微服务、推广搜服务、视频处理、机器学习和大数据服务。

在线微服务是指支撑应用的业务逻辑、产品基础功能的后端服务,它包括接口、 RPC 后端服务、数据访问层服务等;推广搜服务是指为抖音、西瓜视频、懂车帝等 Feed 服务和搜索提供内容列表的后端服务,它们大量应用机器学习模型进行服务优化,属于重度算力要求服务。

视频处理、机器学习和大数据服务属于偏离线的服务,它们为推广搜离线训练、视频处理、数据报表提供数据处理支持,通常运行在 Hadoop、Mesos 等调度系统上。

基于上述业务类型划分 ,云原生技术在字节跳动业务中的落地过程如下图所示:

picture.image

2016 年:启动 自研云引擎(TCE 平台)建设 。 它早期的定位是为内部应用提供快捷高效的服务部署方案,专注于服务的生命周期管理,如创建、升级、回滚、高可用、弹性扩展的容器服务,该阶段的宗旨是快速地支持研发效率、服务易迁移、可观测性等基础能力。

2017 年:启动全面云原生化改造 。在这一阶段,我们完成了今日头条、抖音、西瓜视频等微服务的全量上容器,同时基于自研云平台基础,我们构建并完善了服务框架(Golang 为主)、Mesh 平台、流量平台、监控告警等基础设施。

2019年:“推广搜”云原生化 。这一阶段对“推广搜”为主的物理机服务进行了容器化改造,完成了在线服务体系的全量上云。随着字节业务规模的扩展、业务种类的日趋繁多,集群的维护、稳定性、安全等受到了极大挑战,此阶段更关注集群的稳定性、容灾、抗风险等能力。

2020 年:离线、存储云原生化 。我们推进了离在线混合部署,并且通过字节跳动自研融合调度器丰富在离线调度能力,进一步融合在离线业务体系,优化资源管控,提升了资源效率。

当实施离在线混合部署时,我们往往需要强大的调度器来实现离线业务和在线业务友好共存。事实上,公司早期发展阶段通常不具备完善的技术体系和能力,因此字节如何实现离在线混合部署也历经了一段演进路径,如下图所示:

picture.image

字节跳动基础架构编排调度团队的 使命 是: 推进字节技术体系的云原生化等代际演进,持续优化资源效率

一方面,我们向上提供各种维度、资源类型的弹性资源抽象,推动业务由云原生化改造朝着面向云设计业务的方向演进,让业务在设计架构时,能够天然感知底层的多个维度、多种 QoS 类型的资源,实现 Service 化落地;

另一方面,我们向下要回答一个问题,即为什么字节的机器数量如此庞大,利用率却并不理想,业务仍苦于缺少机器资源。因此字节跳动基础架构编排调度团队需要对数据中心整体的机器资源利用率负责,实现降本提效。

我们的策略体现在由 Partition 向 Share 的演进过程,具体思路是:由最初 Kubernetes 和 YARN 分别管理各自的机器,演进到集群之间的机器级别可以共享,进而演进到机器级别的资源共享,最后实现机器级别更细粒度的资源融合与复用。因此这是一个可实操、可落地、可演进的思路。

从技术路径的角度来说,该思路体现在以下四个阶段:

  • 离线先行 :由于离线业务对资源延迟的容忍度较为灵活,因此可以首先对它进行调度系统的适配,实现对底层弹性资源的复用;
  • 在线大规模弹性伸缩 :同时我们推进了在线编排调度系统,即 Kubernetes 的大规模弹性伸缩,实现了整机级别的资源出让;
  • 攻克技术难点 :并且我们也相应进行了底层隔离技术的攻关和推进,为进一步的资源共享复用提供了基础;
  • 向统一调度系统演进 : 最后在 0/1 混部向常态化混部演进的基础上,我们推进了融合调度系统,实现由统一的资源管理平台、统一的调度系统、统一的隔离机制、统一的机器供给完成对所有业务形态的统一承载。

字节内部称这一编排调度系统为 GödelCloud,它其实是字节基于 Kubernetes,对元数据存储、核心调度器、底层 QoS 管控、数据面隔离等多方位的深度定制和改造的整体集合。字节跳动基础架构编排调度团队基于数据中心操作系统的视角构建了这一体系,实现整体性资源调度。

打一个比方,假设对于一个单机操作系统,比如 Linux,我们需要在它上面同时运行一个用户态的需要实时响应的进程和一个后台处理的进程,当该用户态的进程被唤醒的时候,我们需要快速将后台处理进程的 CPU 时间交付给它。从长期来看,它的 CPU 利用率其实很低。

数据中心操作系统层面的操作也与其类似,当面向终端服务的在线体系需要更多资源时,我们可以抽调离线的大量资源,快速填补在线资源的空缺;并且当在线资源闲置时,又可以将闲置资源分批次快速归还给离线,由此实现整体的资源调度。

混合部署技术

在谈及混合部署技术之前,我们需要先弄清楚服务的核心指标及其内涵。 对于运行在容器、弹性虚机上的服务,我们通常以可用副本数所占的比例来定义它们的可用性。 但是当用户实际使用这些服务时,它们的执行性能和效率才是用户真正关注的重点,而这些事项难以被清晰定义。

因此我们对服务的可用性提供了一些新的解读和延伸扩展——我们不仅需要关注服务的可用副本数占比,同时也要关注它对延迟的容忍度和可重入性。

下图详细展示了一个 Client 访问一个 Cache 缓存的完整链路分解,该链路涉及了 Client 端的用户态代码到 Client 端的协议栈、到网卡、到交换机、到 Server 端的协议栈交换机、再到用户态的处理,最后以相同的路径返回结果的流程。

picture.image

从微观维度来看,当一个服务的响应延迟时,本质是该服务在运行的整个链路过程中受到了相应的影响,比如它可能受到了内核调度的影响,也有可能受到了网络丢包的影响等。

从宏观维度来看,对于一个批式计算服务,比如 Spark SQL 处理一批数据并需要获取相应的结果时,在某一个阶段,它所运行的容器被非预期杀死了,那么它相应的数据 Partition 也需要被重新计算。此时它是由应用层框架进行 failover 重试,因此它具备一定的可重入性。

微服务的可重试性相对弱很多,因为它的报错告警会直接感知到这些重试。然而微观层面的延迟抖动对于 Spark SQL 整体的计算处理过程而言,很难被其感知到。

因此在推进混合部署之前,字节跳动基础架构编排调度团队引入了一些非常高级的监控特性,比如 eBPF、PMU、RDT 等。在服务受到性能影响时,它们能够迅速查明病因。

基于时延容忍度和可重试性两个维度,字节内部的服务被大致划分为以下几种类型:

picture.image

从图中可以看到,大数据批式处理服务具备时延容忍度较高、可重试性较强的特征;与之相反,在线微服务具备时延容忍度较低、可重试性较弱的特征。基于对服务两个维度的划分,我们可以对各种服务分别实施差异化的 QoS 策略和隔离手段。

混部技术架构

字节混部技术架构如下图所示,它分为三个子系统,分别是:以 Kubernetes 核心控制面为主的在线编排调度系统、以 YARN RM 和 AM 为主的离线调度系统、以及由 Sysprobe 和 Hybrid Controller 整体组成的调度系统。

picture.image

混部技术架构的逻辑大致是 :优先满足在线微服务的资源需求,提供剩余的闲置资源给离线服务使用;并且当在线服务需要更多资源时,能够快速抽调离线的资源供给在线服务。

具体而言,Sysprobe 作为一个系统监控,它会拿到单机层面各种容器的资源使用情况,并通过一系列机器学习算法推导出机器上离线侧可使用的资源类型,然后将它出让给 NodeManager,由 NodeManager 动态上报到中心的 RM 来进行资源的统一展示。

此时,一个 Spark 的 AM 就可以基于它的动态混部队列提交任务并执行起来。 中心的 Hybrid Controller 主要负责整体集群的降级容灾策略、水位控制、相关的配置管理等事务。

字节跳动基础架构编排调度团队基于集群的三层调度系统视角来构建混部,包括中心的调度器、节点的调度器以及内核的调度器,它们分别承担了三种不同的资源调度角色。

中心的调度器比如 K8s 和 YARN RM, 它们主要负责完成容器到节点的选择,尽可能平衡资源、稳定负载。但是当节点层面在线服务发生 QoS 抖动时,我们往往需要做出更快的响应,此时分钟级的调度响应延迟是完全不被接受的。

Sysprobe QoS Controller 组件需要实时动态地调整节点的实际资源分配,当在线需要更多资 源时,能够快速地回收资源。至于秒级的响应,由于 Sysprobe QoS Controller 处于用户态的角色,因此它通常会受到单机层面高负载异常情况的影响,也难以做到彻底的兜底。

因此我们还需要在 Kernel 级别,比如 CPU 调度器、 IO 调度器上做一些更深度的定制,实现系统层面更强的兜底能力,更好地保障延迟敏感的服务对 CPU 时间的需求,同时保证吞吐型服务能够获得足够多的 CPU 时间,从而兼顾延迟与吞吐,达到整体效能的最大化。

混部实施效果

基于上述三层调度逻辑设计,以及结合底层诸多原生的和深度定制的隔离机制,我们最终实现了离在线数十万台机器混部的效果。天级平均利用率从原先不到 30% 提升到了 60% 以上,节省了 30% 的机器成本。

picture.image

融合调度系统

实现了离在线混部并不意味着调度系统演进就此终止,整个数据中心的利用率其实还未全面充分得到提升。

一方面,上述混部系统的资源表达、抽象是不完整的,并非所有的离线作业都可以使用不稳定的资源;另一方面,它仍然是两个独立的系统,其资源管理体系、底部机器供给运维都是割裂的,上层平台和周边设施是独立建设的,这就导致了更大范围的共池复用非常困难。

基于此,字节跳动基础架构编排调度团队提出了新一代的编排调度系统:GödelCloud 。

GödelCloud:调度系统终态视图

首先,我们对面向终态的资源类型提供了一个统一的抽象,如下图所示:

picture.image

图中矩形方框代表一个 Queue 的 Guarantee 资源量。当资源出现天级的波峰波谷时,意味着它的天级利用率很低,因此我们设置相应的混部逻辑进行资源回收得到 BestEffort 资源,让离线服务可以充分利用这部分资源。

Offline Guarantee Queue 是针对离线存量的场景,它的本质是通过提升部署率来提升利用率。 我们需要融合两种策略,以更充分地利用资源。

进一步地,我们来看一看调度系统的整体分层架构。在单集群调度层面,调度系统需要一个单集群承载所有资源类型,通过运用统一的调度器、统一的资源管理、统一的隔离能力来实现资源整体的共享复用;然后对接到联邦层实现数据中心层面任务的统一编排、统一调度以及资源管理;下一步对接到上层不同的租户隔离能力以及接入手段;最后对接到 PaaS 平台、机器学习平台、数据平台等不同的业务系统。

picture.image

单集群能力

统一调度

调度系统的核心组件是统一的调度器,调度器需要具备实现融合的调度语义,比如扩展资源类型的定义和实现、Quota 的准入和超用、排队机制和抢占策略、Gang 语义和灵活调度单元。

我们将其实现为 Dispatcher + Schedule + PreBinder 的分布式架构,基于乐观并发的策略实现了一个既能满足在线延迟、又能满足离线吞吐的中心调度器。

picture.image

高性能元数据存储 KubeBrain

引入离线作业会给核心存储带来 10~20 倍的存储压力。尽管我们在原生 Kubernetes 核心管控面上实施了诸多的优化和防护,但仍然难以满足相应的吞吐需求。

基于字节自研的 ByteKV 的高性能存储,字节跳动基础架构编排调度团队自研了 Kubernetes 的元数据存储,基于 KV 封装了对应的 Key + Resource Version 作为对应的索引和数据,实现了对应的 MVCC 和 CAS 操作;并且通过封装 Watch 机制实现了对应的 Informer 推送能力。

在实施效果上,我们实现了 1w 台机器、40w+ 容器的数量;如果以 Gang 语义进行调度,能够在 10 秒内拉起 5k 的容器,展现了极高的吞吐性能。

picture.image

异构资源管理

实现了中心资源管理和调度逻辑后,我们还需要在节点层面进一步扩展,实现各种异构资源混部逻辑的融合复用,使得各种资源类型需求的业务容器能够实现实际物理资源的共享复用。

字节跳动基础架构编排调度团队在原生的 Topology Manager 和 Device Manager 的基础上扩展了 QoS Resource Manager,并且结合混部的策略对 CPU 内存的 NUMA 分配逻辑进行了整体设计,从而更好地实现在单机层面的资源复用。

picture.image

技术接入

Virtual Kubernetes

我们提供了租户接入能力比如 Virtual Kubernetes,它既是一种池化资源的接入能力,同时也为租户提供了完整的控制面定制能力,如下图所示:

picture.image

Yarn on Gödel

字节内场存在大量的离线作业,离线作业的迁移和运维成本通常非常高,因此我们提供了 Yarn on Gödel 方法。

简而言之,我们去掉 YARN 的 Slave 节点,以相关的管控逻辑将它的 Resource Manager 完全 Operator 化,将相应的调度逻辑完全下沉到 Gödel Schedule 中运行,它只保留对应的离线作业的生命周期管理和一些周边能力,从而实现了离在线的无缝迁移和并池能力。

picture.image

Global Scheduling 和 Quota

当我们实现了单集群的统一调度能力后,我们需要进一步打通集群之间的物理的壁垒。

在 2019 年,字节引入了第一代联邦系统,它能够实现很多诸如用户体验、自动容灾、运维效率、多云多集群接入的能力。随着更大范围的离线作业和在线服务的进一步融合,联邦系统也演进到了第二代。第二代联邦系统带来哪些好处呢?

一方面,它提供了更加轻量级的多租户管理能力,让用户看到的是单集群的独占视角,能够保证物理集群、Member 集群层面的资源复用,同时能够实现原生对象和 CRD 对象创建和访问的隔离。

另一方面,我们实现了联邦化 Workload,能够实现全场景的接入。

举例来说,原生或社区的联邦方案、多云多集群管控方案通常只能接入有限的负载类型,而字节内场实现了各种离线大数据场景、机器学习场景等作业的统一接入;并且结合全局的资源管控和优化,能够实现进一步的调度;同时我们也进一步融合离线和在线的容灾体系,实现了整个数据中心层面的资源共享和复用。

picture.image

未来展望

本章节将通过三个案例来和大家分享字节跳动基础架构编排调度团队未来会关注和演进的方向。

融合打通资源池

当联邦层被架设在不同的离线和在线集群之上后,我们通过统一的虚拟化队列管理,实现了离线 到在线 的非常灵活的资源拆借逻辑。

举一个例子,原来在准备活动资源时,可能会涉及大量的运维和搬迁,而现在只需要通过平台调整对应的 Quota ,就可以高效地实现离线到在线的容量切换,实现百万核心分钟级别地交付和梯度式回收。

picture.image

大规模机器学习********

当我们实现了统一的、公平的资源管理后,我们会面向不同领域进行定制化的设计和优化。

举一个例子,在大规模的机器学习场景,我们不仅提供了标准的机 器学习的编排调度能力,以及强化的调度逻辑来保证它的吞吐,提升它的 AUC。

同时我们将各种混部 CPU 、稳定 CPU、微拓扑、非微拓扑、各种 GPU 进行共池混用时,能够和 上层框架的演进逻辑进行深度的结合,获取最佳的成本和性能收益。

picture.image

微服务合并部署

虽然微服务的迭代效率非常高效,但同时它也带来了诸多弊端,比如当微服务的组件被拆分到非常细时,它会带来额外的性能损耗、链路开销、以及网络通信方面的性能问题,造成更多的成本负担。

picture.image

历史合并部署方案的思路是融合微服务各种层面的进程,但这会对实际的编译、部署、监控、治理、隔离等现有的体系产生非常大的冲击。

因此字节跳动基础架构编排调度团队推出了亲和性部署,它既保留了微服务的高效迭代效率,同时又具备了单体服务的执行性能。

亲和性部署的核心逻辑 : 它通过亲和性容器调度,实现了上下游关联性更强的服务能够尽可能同机摆放; 并 且基于中心化流量调度策略,保证单机层 面上下游的服务尽可能同机访问; 然后由原来 的远程 TCP 协议切换到了单机层面,通过共享内存去序列化来加速进程之间的通信效率; 最终在核心服务的试点上,节省了 20% 以上 CPU 利用率。

  • END -

下载云原生白皮书

基于字节跳动基础架构提供的云原生技术能力和技术实践,火山引擎已经构建了全栈的云原生服务产品矩阵,包括面向算力的云原生服务、面向应用的云原生服务和面向场景的云原生服务三大板块。

欢迎下载 IDC 和火山引擎联合出品的云原生白皮书,获取企业数字化转型新理念!

picture.image

扫描二维码,下载火山引擎云原生白皮书

加入我们

字节跳动基础架构产品运营团队,作为架构各组件产品对外表达和用户信息反馈的桥梁,支持架构各组件的产品运营工作。 在字节跳动,产品运营团队对产品的影响力打造、产品增长、用户体验负责,并提供横向运营能力支持,具备完整的产品市场能力和全链路产品运营能力。

联系人:xuhuan.1503@bytedance.com

点击【 阅读原文 】,加入我们!

86
0
0
0
关于作者
相关产品
评论
未登录
看完啦,登录分享一下感受吧~
暂无评论