以 Kubernetes 为代表的云原生技术底座支撑了字节跳动业务的快速发展。从微服务场景开始,Kubernetes 逐渐演化统一支撑了字节内部的大数据、机器学习以及存储服务等多种形态基础设施。
1.1 技术体系概览
从技术体系的底层逻辑上来看,字节跳动采用的是一套清晰的分层技术体系。一些常见的前台业务,比如今日头条、抖音、西瓜视频等都建立在一系列共享的技术中台和基础设施服务上。
基础架构必须不断地演化自身的平台服务能力,才能适应业务的快速发展。
举个例子,字节跳动目前有超过 10 万个在线服务,在线集群中有超过一千万的 Pod,这些服务每天都有超过 2 万次的变更。平均来看,字节的业务系统每五天就会更新一遍。为了处理数据报表和机器学习训练,每天有超过 1.5 亿的离线任务数量处理数十 EB 的存储资源。
字节的基础设施面临的是一个规模巨大且持续快速变化的业务场景。
1.2 字节云原生推进历程
在快速变化和规模挑战下,云原生技术,特别是与云原生相关的资源调度技术在字节是如何发展的呢?
目前基础架构的重点建设领域是基于联邦化的多集群资源的统一管理和统一调度。
1.3 字节云原生发展动机
从研发和资源效率来看:
从研发和资源效率来看:
我们把和云原生相近的技术体系分成了 DevOps、Cloud Native 以及 Serverless 三代。
这三代技术总体是沿着两个路径在往前推进,分别是产品前向一体化,以及资源规模化。这两种思路从两个角度分别推动着技术体系的演进。
从技术体系迭代来看,字节跳动技术体系往后迭代方向可以总结为下面的主题:
我们希望朝这些主题方向努力,最终形成下一代的 Serverless 基础设施。
在大量字节业务完成了云原生改造,实现了资源统一托管之后,从全局来看,如何才能够高效地管理并经营好集团资源,这是我们首先面临的问题。要回答好这个问题,需要先解释理想状态下的资源管理模型。
在资源管理的理想状态下,我们给开发者提供的是一个统一的资源入口,在这个入口下,用户可以从统一的资源池获取资源。
在面向业务和应用方面,我们希望开发者可以极度灵活地获取所需资源,像获取“自来水”一样获取各种形态的资源。虽然他们自身的资源需求复杂,有各种各样形态和要求,但是都可以做到随用随取、随取随有的状态。
在资源管理方面,我们希望给用户呈现的是统一的资源池场 —— 一个充分并池混合的资源池。这个资源池具备全局最优的资源效率,能够统一管理多区域、多计算架构的资源。不同的业务形态和团队之间的资源就可以灵活调配。
但落实到实际资源需求场景,各业务用户对于资源的需求是极度复杂的。
从整体来看,字节内部目前托管的平台租户包含在线服务、机器学习平台、数据平台, FaaS 以及部分的存储业务。这些平台租户的应用模型有很大的差别,包含无状态的应用模型、有状态的模型、批式应用等等。
除了业务场景的复杂需求外,安全、性能以及容灾等方面也会为底层的资源管理带来冲击:
总体来看,资源统一管理有挑战也会带来可观的收益。在实际执行过程中我们需要适当的结合运营、运维和调度等手段,达到有效的资源管理。
2.1 统一资源管理挑战与收益
这里我们总结了资源统一管理方面的挑战和收益。
挑战:
收益:
2.2 资源统一解决思路
为了解决资源统一管理这个问题,我们提出了三个思路:
1)抽象能够提供的资源售卖模型,方便不同的业务线、业务系统准确地表达自身的需求;
2)创建一套统一的 Quota 管理平台,这个平台可以让开发者们灵活地管理自身的各类资源;
3)资源分层调度系统使得单机集群对字节内部所有计算资源做到快速灵活的交付。
2.2.1 资源模型抽象:QoS & 弹性分级
在资源模型方面,我们给应用提供的资源形态以 CPU 维度为例一共分为三级:
目前字节内部的应用弹性资源交付也是有三类诉求:
2.2.2 分层资源调度
如何有效地把资源诉求准确高效地交付到开发者手上需要一套完整的调度系统来支持。字节内部是通过一套分层的调度系统来实现调度交付的。
单机调度主要是扩展了 Kubernetes 的单机资源管控:资源的微拓扑结构感知和资源的分配策略,主要解决了如何让不同 cores 形态的 Pod 统一运行在一个节点之上。Kubelet 内新增的 QoS Resource Manager 这个组件,主要负责容器的资源管控链路上按照应用的微拓扑亲和性要求给 Pod 分配包括 CPU 内存以及 GPU 网卡等设备,在单机拓扑结构上的信息可以通过 CRD 上报到调度器,以调度器中心抢占或者调度的形式把 Pod 分配到合适的节点上。同时这个组件能够在框架上灵活的扩展。
SysAdvisor 是一套单机层面的策略管控实现的组件,可以持续观察 Pod 在细粒度上面的系统指标如何结合不同业务形态的资源使用模型去做预估,去决策在每一个资源维度上如何给 Pod 分配合适的资源量。
集群中心调度器需要解决的核心问题是如何让不同形态的应用在整个集群里自由地调度。需要满足不同的调度语义细粒度的要求,充分降低集群空置率。在调度性能方面,同时要满足低频次和批式的大吞吐的调度场景。针对各种应用场景提升调度场景的质量也是集群中心调度器需要解决的问题。
下图总结了调度功能层面下不同场景对于调度器的需求:
目前字节使用的调度器是参照 Kubernetes 框架的分布式调度器。这套调度系统主要的中心式组件有 Dispatcher、并行式的 Scheduler 还有中心式的 Binder。
其中,Dispatcher 主要负责把应用以及集群内部的节点资源分配到具体的 Scheduler 上。Scheduler 在主体结构和 Kubernetes 原生的调度器结构类似,主要处理的就是 predicate 和 priority 的调度计算逻辑。Binder 可以解决不同 Scheduler 视角下调度结果的冲突,并且用 SchedulingUnit 替换了原生的 Pod 语义。这样可以更加方便地处理常驻任务中 per Pod 调度以及批式场景下的 per batch 调度。
当集群整体的资源占用水位很满的状态下,乐观并发调度中很容易出现调度冲突的问题。我们的解决思路是在 Scheduler 的每次响应结果里,针对调度申请给出多个候选节点,然后统一送到 Binder 里去解决冲突,这个设计可以降低 Binder 里解决冲突的失败概率。
过去的混部方案是基于 Kubernetes 和 Yarn 的联合系统管控的方案,并在每一个节点上同时运行 Kubernetes 和 YARN 的管控组件。此外还有一个居中的协调组件负责分配两套系统分别可见的资源量。在联合管控的模式下,单机层面每个节点里 agent 占用资源量级不大,但在整个集群里是一个非常可观的资源量。如果能够实现一套统一的链路, 管理不同形态的资源,对于资源优化的架构以及效果都能得到不错的简化和收益。
在新的统一调度架构下,我们的混合部署架构也做了一系列的调整。保留了平台层 Kubernetes 的 API 以及 Yarn 的 Resource manager 两个入口部署应用的能力。底层的系统上是全部收敛到了基于 Kubernetes 的管控系统上,可以实现大数据系统平稳的底层系统的切换工作。
在新的架构上,不论是在线服务还是离线作业的 Pod 都可以通过一个公共的 Kubernetes API 以及统一调度器去安排资源的调度。这样不仅实现了资源分级模型上管控链路的复用途径,有更大的空间考虑在线、离线业务在同一个集群中运行时资源层应该如何分配及协作。
2.2.3 全局调度
考虑到字节跳动的整体规模,单一的集群能力不足以满足管理字节全球数据中心的需求,并且在应用之间的隔离、多区域的容灾以及算力的标准化问题上字节也有更加细粒度的调度要求。
为了解决在一百万节点的规模下处理好全局范围内资源和业务维度之间的匹配问题,字节跳动的全局调度器加入了联邦层,可以实现大颗粒度的应用和资源调度匹配逻辑。
在应用方向上,我们以应用的优先级作为主维度;在资源池方面,我们以机房作为主维度,这两个方面交叉搭配就形成了一个应用整体粒度上可以全局调度的分配空间。应用和资源的维度是很多的,如果我们选择过多的资源维度,全局的资源会被划分成过多的碎片,不利于管理。所以选取主维度需要考虑对于每一个资源池容量的影响不能低于设定的节点数量。
字节现有的全局调动器主要参考社区的 KubeFed V2 的框架。在社区的基础之上,我们也实现了两方面的扩展,一是关于联邦层访问语义的透明化改造。这个改造使得我们上层平台可以使用原生的Kubernetes 资源对象去操作底层资源,从而降低平台接入联邦资源池的成本。二是大面积改造了全局调度,使得多机房的容灾业务线之间的安全隔离,以及多代际标准算力等都可以在全局调度上统一实现。
目前字节内部各种形态的计算应用都实现了全量的云原生化以及资源层面的统一,整个集团全局的计算资源利用率平均超过 40%。
虽然仍然有提升的空间,但是利用率在可以预见的未来里很快就会达到瓶颈。我们认为下一代的基础设施依然是会沿着产品前向一体化以及资源规模经营两个方向去开展。
3.1 微服务治理
在产品演进方面,以微服务治理为例,字节跳动目前有超过 10 万个微服务来支撑系统建设,而这些微服务之间有着复杂的依赖关系。
上图是从生产环境里抓取的子业务线服务的拓扑结构,这个图里每个节点代表一个具体的微服务,而节点之间的边就代表服务之间的依赖关系。
在服务架构治理方面,因为这些服务都是散落在不同的业务团队和系统里,很难通过一个全局的视角去做架构层面的迭代,就会造成一些老的服务没有办法下线。
业务和业务系统之间的依赖关系也是直接在底层服务之间通过远程调用的方式实现。在跨业务线交互的场景里直接暴露细粒度的服务接口会使得服务架构治理的复杂度变得很大,往往需要牵涉多个部门协同工作才能推进服务的架构演进。
所以在微服务的产品层面,只需一套面向应用的解决方案去管理一个子业务线内所有的服务。
在资源开销方面,业务系统通过网络调用的方式实现互联,会有很多的数据资源花费在网络通信加解密上。随着微服务数量越来越多,这方面的资源开销也会变得越来越大。目前字节内部在推广函数类的平台,越来越多的服务会通过更细粒度的函数形式去表达自身的逻辑,微服务侧就会趋向于更加微小的方向。那么在架构治理以及资源开销方面的挑战会变得更加巨大。
3.2 资源利用率 vs. 资源有效利用率
资源层面在之前都是围绕着集群的底层资源平均利用率去展开优化,通过混合部署、弹性扩缩以及分时复用等多种形式取得了不错的平均利用率的优化效果。但是底层的资源利用率和实际的业务成本之间依然存在很大的代沟。如何更直接地解决应用层面的容量成本问题,是我们下一步需要重点关注的方向。
3.3 第三代基础设施产品迭代
总结来看,下一代基础设施在微服务这个领域有几个重点的的技术方向。
以上实践经验我们把它总结成了 KubeWharf 开源项目并反馈到社区,感兴趣的同学可以了解更多相关内容。
同时,作为字节跳动旗下的云服务平台,火山引擎抽象了字节跳动的云原生实践思想,已经对外推出了包含上层解决方案和中层基础产品服务的云原生全系产品。
其中,云原生底座包含核心容器服务和镜像仓库两大产品,它们沉淀了字节跳动数年来建设容器平台的经验,除基本应用托管能力外,还提供高稳定、高性能、自运维等能力。
基于应用生命周期拆解,火山引擎也已推出一些包含持续交付等提升敏捷化和统一交付能力的产品,也有服务网格、应用观测、应用韧性这类可以从流量、监控、演练等方面保障业务平稳运行的产品。
字节跳动宣布开源 KubeWharf,一个实践驱动的云原生项目集
字节跳动基于大规模弹性伸缩实现拓扑感知的在离线并池
KubeZoo:字节跳动轻量级多租户开源解决方案
字节跳动云原生微服务多运行时架构实践