Google 大规模集群管理器 Borg


本文是 Google Borg 论文的译文,从事 Kubernetes 相关的工作几年来,一直惦记着这篇论文,所以就花了一点时间翻译了一下。后续还需要花时间校正,有些翻译的名词个人觉得也不太合适,不过先凑合着看吧,自己完整过一遍还是感觉不一样的。

1. Abstract

Google Borg 系统是一个集群管理器,运行着数千个应用程序的数以十万计的作业,跨多个由数万台机器组成的集群。

Borg 通过结合准入控制、高效 task packing、超配、机器共享和进程级性能隔离,实现高效的资源利用率。它通过运行时特性支持高可用应用,最大限度减少故障恢复时间,并且通过调度策略降低相关故障发生的可能性。Borg 还提供声明性 job 规范语言、名称服务集成、实时 job 监控以及分析和模拟系统行为的工具,从而简化用户操作。

2. Introduction

集群管理系统的内部代号是 Borg,它全程管理、调度、启动、重启以及监控 Google 运行的应用程序。

Borg 提供三个好处:

  1. 向用户隐藏资源管理和故障处理的细节,用户只需专注于应用程序开发
  2. 高可靠性和高可用性的操作,同时支持应用程序相关特性
  3. 有效的在数以万计的机器上运行工作负载
borg-arch.png

3. The user perspective

Borg 的用户是运行 Google 应用程序和服务的 Google 开发者和系统管理员(Google 内部称为 Site Reliability Engineers,简称 SRE)。用户以作业( jobs )的形式向 Borg 提交工作,每个 job 由一个或多个运行相同程序(二进制)的任务( tasks )组成。每个 job 运行在一个 Borg cell (一组作为单元统一管理的机器)上。

3.1. The workload

Borg cells 运行异构的 workload,主要包括两部分。第一种是那些长时间运行、理论上“永不宕机”的服务,它们处理短生命周期且延迟敏感的请求(几微秒到几百毫秒之间)。这类服务一般用于直接面向终端用户的产品,如 Gmail、Google Docs 和 Web 搜索,以及内部基础设施服务(如 BigTable)。另外一种是运行几秒到几天即可完成的批处理作业,这类服务对短期性能波动不太敏感。

一个典型的 cell,一般分配 70% CPU 资源,实际使用为 60%,分配 55% 的内存资源,实际使用为 85%。

3.2. Clusters and cells

一个 cell 的机器都归属于单个集群,通过高性能的数据中心级别的光纤网络连接。一个集群部署在一个独立的数据中心建筑中,多个数据中心建筑构成一个 site 。一个集群通常包括一个大规模的 cell 和许多小规模的测试或者特殊目的的 cells。尽量避免单点故障。

排除测试 cells,一个中等规模的 cell 一般由 10k 机器组成。一个 cell 中的机器规格是不同的,诸如配置(CPU、RAM、磁盘、网络),处理器型号,性能等方面。用户无需关心这些差异,Borg 确定在哪个 cell 上运行任务,分配资源,安装程序和依赖项,并监控应用运行状况以及在运行失败时重启。

3.3. Jobs and tasks

一个 Borg job 的属性包括名字、属主以及 tasks 数量。通过一些约束,可以强制 job 的 tasks 在具有特定属性的机器上运行,例如处理器架构、操作系统版本,或者外部 IP 地址。约束可以是硬约束,也可以是软约束;软约束更像偏好而不是强制要求。可以推迟一个 job 的启动时间,如在另一个 job 完成之后再启动。一个 job 只能运行在一个 cell 上。

每个 task 映射为一组运行在某台机器容器中的 Linux 进程。绝大多数 Borg workload 都不运行在虚拟机中,一方面是因为我们不想支付虚拟化成本,另一方面是 Borg 设计之初,Google 已经大量投入没有硬件虚拟化支持的处理器。task 也有属性,例如资源需求以及它在 job 中的索引。大多数 task 属性同它们的 job 一样,不过也可以被覆盖,例如提供 task 专用的命令行参数。每个资源维度(CPU 核、内存、磁盘空间、磁盘访问速率、TCP 端口等)都可以独立细粒度指定。Borg 程序会静态链接以减少对运行时环境的依赖,并组织成由二进制和数据文件构成的软件包,软件包安装由 Borg 编排。用户通过 RPC 与 Borg 交互来操作 job,最常见的是通过命令行工具、其它 Borg jobs 或监控系统。大部分 job 描述文件是用声明式配置语言 BCL 编写的;BCL 是 GCL 的变体,会生成 protobuf 文件,并扩展了一些 Borg 专用关键字。

borg-job-task-state.png

用户可以修改一个运行中的 job 属性值并发布到 Borg,然后 Borg 按照新的 job 配置来更新 tasks。更新通常是以滚动方式完成,并且可以对更新导致的任务中断(重新调度或者抢占)的数量进行限制,任何导致更多中断的更改都会被跳过。

tasks 可以请求在被 SIGKILL 抢占之前,先通过 Unix SIGTERM 信号获得通知,以便有时间进行清理、保存状态、完成当前正在执行的请求并拒绝新的请求。如果抢占方设置了延迟上限,实际通知时间可能会更短。在实践中,大约 80% 的情况下可以送达通知。

3.4. Allocs(allocation)

Borg alloc (allocation 的缩写)是一台机器上的一组预留资源,可以在其中运行一个或多个 tasks;无论是否使用,这些资源都会保持分配。Allocs 可以用于为未来的 tasks 预留资源,在停止和再次启动 task 之间保留资源,也可以将不同 jobs 的 tasks 聚集到同一台机器上,例如一个 Web server 实例及其关联的 logsaver task,后者会把 server 的 URL 日志从本地磁盘复制到分布式文件系统。一个 alloc 的资源和机器资源类似,运行在同一个 alloc 中的多个 tasks 会共享这些资源。如果一个 alloc 必须迁移到另一台机器,它的 tasks 也会随之重新调度。

一个 alloc 集合和 job 很像,它是一组分配在多台机器上的预留资源。一旦创建一个 alloc 集合,就可以提交一个或多个 jobs 运行在其中。为简洁起见,通常使用 "task" 引用 alloc 或者一个顶级的 task(alloc 之外的 task) 和 "job" 来引用一个 job 或者 alloc 集合。

3.5. Priority, quota, and admission control

当到来的工作超过系统可容纳的规模时,Borg 通过优先级和配额来处理。每个 job 都有一个 priority 优先级,一个小的正整数。高优先级的 task 可以以牺牲较低优先级 task 为代价来获取资源,甚至通过抢占(杀死)后者实现。Borg 为不同用途定义了互不重叠的优先级区间,按优先级从高到低包括:监控、生产、批处理和 best effort(也称 testing 或 free)。

被抢占的 task 通常会在 cell 的其它地方重新调度,但如果高优先级 task 挤掉稍低优先级 task,后者又挤掉更低优先级 task,就可能产生抢占级联。为了消除大部分这种情况,Borg 禁止生产优先级区间内的 tasks 互相抢占。优先级表达的是在 cell 中正在运行或等待运行的 jobs 的相对重要性。 Quota 配额用于决定哪些 jobs 可以被准入调度。配额表示为一段时间内(通常为几个月)给定优先级的一组资源量向量(CPU、RAM、磁盘等)。这些值指定了用户的 job 请求在同一时间可以申请的最大资源量。配额检查是准入控制的一部分,而不是调度的一部分;配额不足的 job 会在提交时立即被拒绝。

高优先级配额比低优先级配额成本更高。生产优先级配额受限于 cell 中实际可用资源,因此提交了符合配额的生产优先级 job 的用户可以预期它会运行,前提是不受碎片化和约束影响。虽然我们鼓励用户不要购买超过实际需要的配额,但很多用户会超买,以避免应用用户增长后出现资源短缺。我们的应对方式是在较低优先级层级超卖配额:每个用户在优先级 0 都有无限配额,不过由于资源超订,这通常很难真正使用。低优先级 job 可能被准入,但因为资源不足一直处于 pending(未调度)状态。

配额分配在 Borg 之外处理,并和物理容量规划密切相关,其结果会反映在不同数据中心的配额价格和可用性上。只有具备所需优先级下足够配额的用户 jobs 才会被准入。配额机制减少了对 Dominant Resource Fairness(DRF)这类策略的需求。Borg 还拥有 capability 系统,给予某些用户特殊权限,例如允许管理员删除或修改 cell 中的任意 job,或者允许用户访问受限的内核功能或 Borg 行为,如在其 jobs 上禁用资源估计。

3.6. Naming and monitoring

只是创建和放置 tasks 还不够,服务客户端和相关系统还需要能够访问到对应的服务,即使这些服务被重新调度到新的机器上。因此,Borg 会为每个 task 创建一个稳定的 "Borg name service"(BNS)名称,其中包括 cell 名、job 名和 task 编号。Borg 用这个名字将 task 的主机名和端口写入 Chubby 中一个一致且高可用的文件,该文件用于 RPC 系统查找 task endpoint。BNS 名也是 task DNS 名的基础,如用户 ubar 在 cell cc 上执行的 job jfoo 的第 50 个 task,可以通过 50.jfoo.ubar.cc.borg.google.com 访问。Borg 还会在发生变化时把 job 大小和 task 健康信息写入 Chubby,以便负载均衡器知道应将请求路由到哪里。

几乎所有运行在 Borg 上的 task 都包含一个内建的 HTTP server,用于发布 task 的健康信息和数千个性能指标(如 RPC 延迟)。Borg 监控健康检测 URL,并在 tasks 没有及时响应或者返回 HTTP 错误码时重启它们。其它数据会被监控工具追踪,展示在 dashboards 上,并在服务级别目标(SLO)违背时触发告警。

名为 Sigma 的服务提供了一个 Web 用户界面,用户可以通过它检查自己所有 jobs 的状态、查看特定 cell,或者深入查看各个 jobs 和 tasks,检查它们的资源行为、详细日志、执行历史以及最终命运。应用程序会产生大量日志,这些日志会自动轮转以避免磁盘空间耗尽,并且在 task 退出后保留一段时间以协助调试。如果一个 job 没有运行,Borg 会提供一个 "why pending?" 注释,并给出如何修改 job 资源请求以更好适配 cell 的指导。

Borg 记录所有 job 提交和 task 事件,以及详细的逐 task 资源使用信息,并将这些信息记录在 Infrastore 中。Infrastore 是一个可伸缩的只读数据存储,并且由 Dremel(Google 交互式数据分析系统)提供类 SQL 的交互式接口。数据被用于按使用量计费、调试 job 和系统故障以及长期容量规划。它也提供了 Google 集群工作负载跟踪数据。

所有的这些特性帮助用户理解和调试 Borg 以及他们的 jobs,并且帮助我们的 SREs 每人管理数万台主机。

4. Borg architecture

一个 Borg cell 由一组主机组成,一个名为 Borgmaster 的逻辑集中控制器,和一个名为 Borglet 的代理进程组成,Borglet 运行在 cell 中的每个主机上。所有的 Borg 组件都是通过 C++ 编写的。

4.1. Borgmaster

每个 cell 的 Borgmaster 包含两个进程:主 Borgmaster 进程和一个独立的调度器。主 Borgmaster 进程处理客户端 RPC 请求,这些请求要么改变状态(如创建 job),要么提供只读数据访问(如查找 job)。它还管理系统中所有对象的状态机(如机器、tasks、allocs 等),和 Borglets 通信,并提供一个 Web UI 作为 Sigma 的备份。

Borgmaster 在逻辑上是一个单一进程,但实际上会复制五份。每个副本都在内存中维护大部分 cell 状态的副本,并且这个状态也会记录在一个高可用、分布式、基于 Paxos 的存储中,该存储位于这些副本的本地磁盘上。每个 cell 会选举出一个 master,同时作为 Paxos leader 和状态修改者,处理所有变更 cell 状态的操作,例如提交 job 或终止某台机器上的 task。master 会在 cell 启动和已选 master 失效时通过 Paxos 选举产生;它会获取一个 Chubby 锁,以便其它系统可以找到它。选举 master 并故障转移到新的 master 通常需要约 10s,但在大型 cell 中,因为部分内存状态需要重建,可能需要一分钟。当副本从中断中恢复时,它会从其它最新的 Paxos 副本动态重新同步状态。

Borgmaster 在某个时间点的状态称为 checkpoint,其形式是保存在 Paxos 存储中的定期快照加变更日志。Checkpoint 有多个用途,包括将 Borgmaster 的状态恢复到过去的任意点(例如,恢复到刚接受某个触发 Borg 软件缺陷的请求之前以便调试);在极端情况下进行手工修复;为将来的查询构建持久事件日志;以及离线模拟。

一个名为 Fauxmaster 的高保真 Borgmaster 模拟器可以用于读取 checkpoint 文件,并包含生产 Borgmaster 代码的完整副本,以及 Borglets 的存根接口。它接收 RPCs 来进行状态机变更和执行操作,如 "调度所有待处理的任务",我们使用它来调试失败,通过与它进行交互就好像它是一个实时 Borgmaster,利用 checkpoint 文件模拟 Borglets 重放真实交互。用户可以按步执行并观察过去实际发生的系统状态变化。Fauxmaster 还可以用于容量规划("这种类型的新 jobs 多少适合?"),以及在变更 cell 配置前进行健全性检查("这次变更是否会驱逐其它重要的 jobs?")。

4.2. Scheduling

当提交一个 job 后,Borgmaster 会将它持久记录在 Paxos 存储中,并将 job 的 tasks 加入 pending 队列。调度器会异步扫描该队列,如果有足够的可用资源满足 job 约束,则将 tasks 分配到机器上。(调度器主要针对 tasks 操作,而不是 jobs。)扫描按优先级从高到低进行,在同一优先级内通过轮询方案调节,以保证用户之间的公平性,并避免被大型 job 阻塞队首。调度算法由两部分组成:可行性检查,用于寻找 task 可以运行的机器;评分,用于从可行机器中选择一台。在可行性检查中,调度器会找到一组既满足 task 约束、也有足够“可用”资源的机器,这些可用资源包括分配给可驱逐的低优先级 tasks 的资源。在评分中,调度器会评估每台可行机器的“好坏”。评分会综合用户指定的偏好,但主要由内置标准驱动,例如最小化被抢占 tasks 的数量和优先级,选择已经拥有 task 软件包副本的机器,将 tasks 分散到电力和故障域中,以及 packing 质量,包括把高优先级和低优先级 tasks 混布到同一台机器上,以便高优先级 tasks 在负载峰值时扩展。

Borg 最初使用 E-PVM 的一种变体进行评分,它可以跨异构资源生成单一成本值,并在放置 task 时最小化成本变化。在实践中,E-PVM 最终会把负载分散到所有机器上,为负载峰值留下余量,但代价是增加碎片化,特别是对那些需要占用大半台机器的大型 tasks;我们有时称之为 "worst fit"。

光谱的另一端是 "best fit",它尝试尽可能紧密地填充机器。这会让一些机器没有用户 jobs 运行(它们仍然运行存储服务器),因此放置大型 tasks 会很直接;但紧密 packing 会放大用户或 Borg 对资源需求估计错误的代价。这会损害具有突发负载的应用程序,对于为了易于调度并尝试机会性利用未使用资源而声明低 CPU 需求的批处理 jobs 尤其糟糕:20% 的非生产 tasks 请求少于 0.1 个 CPU 核。

我们当前的评分模型是一个混合模型,它试图减少搁浅资源的数量,也就是那些因为机器上的另一种资源已被完全分配而无法使用的资源。对于我们的 workloads,它提供的 packing 效率比 best fit 高约 3-5%。

如果评分阶段选择的机器没有足够的可用资源来容纳新 task,Borg 会从最低优先级到最高优先级依次抢占(杀死)低优先级 tasks,直到可以容纳为止。我们将被抢占的 tasks 加回调度器的 pending 队列,而不是迁移或者休眠它们。例外情况是为 Google Compute Engine 用户提供虚拟机的 tasks 会被迁移。

Task 启动延迟(从 job 提交到 task 开始运行的时间)是一个已经受到并继续受到大量关注的领域。它的变化很大,中位数通常约为 25s。软件包安装大约占总时间的 80%:一个已知瓶颈是写入软件包的本地磁盘竞争。为了减少 task 启动时间,调度器更倾向把 tasks 分配到已安装必要软件包(程序和数据)的机器上:大多数软件包是不可变的,因此可以共享和缓存。(这是 Borg 调度器支持的唯一数据局部性形式。)此外,Borg 使用树形和类似 torrent 的协议将软件包并行分发到机器。

另外,调度器使用多种技术使其扩展到数万台主机的 cells。

4.3. Borglet

Borglet 是 cell 中每个主机上运行的本地 Borg agent。它负责启动和停止 tasks;如果失败了就重启它们;通过操作系统内核设置来管理本地资源;滚动调试日志;并且汇报所在主机状态给 Borgmaster 和其它监控系统。Borgmaster 每隔几秒轮询 Borglet 以检索主机的当前状态并向其发送未完成的请求。这使得 Borgmaster 可以控制通信速率,避免需要明确的流控机制,并防止恢复风暴。

被选举的 master 负责准备发送信息给 Borglets 并且通过它们的响应来更新 cell 的状态。为了提升性能,每个 Borgmaster 副本运行一个无状态的链接分片来处理与某些 Borglet 的通信;每当 Borgmaster 选举发生时,都会重新计算分区。为了弹性,Borglet 始终报告其完整状态,但链接分片通过报告的信息和机器状态的差异来聚合和压缩此信息,以减少选定 master 的更新负载。

如果 Borglet 多次没有响应轮询信息,则将其主机标记为关闭,并重新调度主机上的 tasks。如果恢复响应,Borgmaster 会通知 Borglet 杀死那些已经重新调度的 tasks,以避免重复。Borglet 即使失去和 Borgmaster 的联系也会继续正常运行,因此即使所有的 Borgmaster 副本失败,当前正在运行的任务和服务也会保持正常运行。

4.4. Scalability

我们还不确定 Borg 集中式架构的最终可扩展性限制会来自哪里;到目前为止,每次接近瓶颈时,我们都设法消除了它。一个 Borgmaster 可以在一个 cell 中管理数千台机器,并且有几个 cells 的到达率超过每分钟 10,000 个 tasks。一个繁忙的 Borgmaster 使用 10-14 个 CPU 核和最多 50GiB 内存。我们使用多种技术来实现这种规模。

早期版本的 Borgmaster 有一个简单的同步循环,用来接收请求、调度 tasks 并与 Borglets 通信。为了能处理更大的 cells,我们将调度器拆分为一个独立进程,使它可以与其它为了容错而复制的 Borgmaster 功能并行运行。调度器副本在 cell 状态的缓存副本上运行。它会重复以下流程:从被选举的 master 检索状态变化(包括已分配和 pending 的工作);更新本地副本;执行一次调度遍历以分配 tasks;并通知被选举的 master 这些分配。master 会接收并应用这些分配,除非它们不合适(如基于过期状态),这种情况下它们会在调度器下一轮遍历中被重新考虑。这在精神上与 Omega 中使用的乐观并发控制非常相似,实际上我们最近在 Borg 中添加了为不同 workload 类型使用不同调度器的能力。

为了提升响应时间,我们添加了独立线程来与 Borglets 通信并响应只读 RPC。为了获得更高性能,我们又把这些功能分片(分区)到 5 个 Borgmaster 副本上。结合这些手段,UI 的 99%ile 响应时间保持在 1s 以内,Borglet 轮询间隔的 95%ile 保持在 10s 以内。

有几件事让 Borg 调度器更具扩展性:

Score caching (评分缓存):评估一台机器的可行性和评分成本很高,因此 Borg 会缓存评分,直到机器或 task 的属性发生变化。例如,机器上的某个 task 终止、某个属性被修改,或者 task 的需求发生变化。忽略资源数量的微小变化可以减少缓存失效。 Equivalence classes (等价类):一个 Borg job 中的 tasks 通常拥有相同的要求和约束,因此 Borg 不会为每台机器上的每个 pending task 判断可行性并为所有可行机器评分,而是只对每个等价类中的一个 task 做可行性检查和评分;等价类是一组具有相同需求的 tasks。

Relaxed randomization (放宽随机化):计算大型 cell 中所有机器的可行性和分数是极大浪费的,因此调度器会以随机顺序检查机器,直到找到“足够多”的可行机器进行评分,然后在这个集合中选择最好的机器。这减少了 tasks 进入和离开系统时所需的评分和缓存失效量,并加快了将 tasks 分配给机器的速度。放宽随机化有点类似 Sparrow 的批量采样,同时还处理优先级、抢占、异质性和软件包安装成本。

在我们的实验中,从头开始调度一个 cell 的整个 workload 通常需要几百秒时间,但是在上述技术被禁用后,超过 3 天仍未完成。通常情况下,对 pending 队列的一次在线调度遍历会在半秒内完成。

5. Availability

borg-evictions-per-task-week.png

失败是大规模系统的常态:上图提供了 15 个样本 cells 中任务驱逐原因的细分。运行在 Borg 上的任务使用诸如复制、存储持久化状态在分布式文件系统中,以及(如果适用)偶尔检查点等技术来处理此类事件。即便如此,我们仍试图减轻这些事件的影响。例如,Borg:

  • 如果有必要,在新的主机上自动重新调度被驱逐的 tasks
  • 通过在主机、机架和电源域等故障域中分散 job 的 tasks 来减少相关故障
  • 限制 task 中断的允许速率以及在维护活动(如操作系统或主机升级)期间可同时停机的 job tasks 数量
  • 使用声明性的期望状态表示以及幂等操作,以便失败的客户端可以无害的重新提交任何被遗忘的请求
  • 速率限制从无法访问的机器中查找任务的新位置,因为它无法区分大规模故障和网络分区
  • 避免重复 task::machine 配对导致任务或主机崩溃
  • 通过反复重新运行 logsaver task 来恢复写入本地磁盘的关键中间数据,即使它附加的 alloc 已终止或移动到另外一台主机。用户可以设置系统持续尝试的时间,几天时间是很常见的

Borg 的一个关键设计功能是,即使 Borgmaster 或者运行 tasks 的 Borglet 出现故障,已经运行的 tasks 仍会继续运行。但是保持 master 运行仍然很重要,因为当它宕机时,无法提交新的作业或更新现有的作业,并且无法重新调度故障主机的 tasks。

Borgmaster 使用多种技术组合,使其在实践中实现 99.99% 的可用性:通过复制应对机器故障;通过准入控制避免过载;使用简单的低级工具部署实例,以最大限度减少外部依赖。每个 cell 相互独立,以最小化相关操作员错误和故障传播的可能性。这些目标,而不是可扩展性限制,才是反对更大 cells 的主要理由。

6. Utilization

Borg 的主要目标之一是有效利用 Google 的主机,这是一笔巨大的金融投资:提高几个百分点的利用率可以节省数百万美元。本节讨论并评估 Borg 用于执行此操作的一些策略和技术。

6.1. Evaluation methodology

我们的 jobs 有放置约束,需要处理罕见的工作负载峰值;我们的机器是异构的,并且我们会在从服务 jobs 回收的资源中运行批处理作业。因此,为了评估策略选择,我们需要一个比“平均利用率”更精细的指标。经过大量实验,我们选择了 cell compaction:给定一个 workload,通过移除 cell 中的机器,找出它最小能被装进多小的 cell,直到 workload 无法再放入为止,并反复从头重新打包 workload,以确保不会卡在某个不走运的配置上。这提供了清晰的终止条件,并便于自动化比较,同时避免了合成 workload 生成和建模的陷阱。

没有办法在生产环境 cells 上实验,但是我们使用 Fauxmaster 获取高保真模拟结果,使用来自实际生产 cells 和工作负载的数据,包括所有约束,实际限制,预留和使用数据。这些数据来自 Borg checkpoints 于周三 2014-10-01 14:00 PDT。(其它 checkpoints 也产生了类似的结果。)我们在消除特殊用途的前提下,选择了 15 个 Borg cells 进行报告,测试小型(小于 5000 主机)cells,然后对剩余种群进行取样,以在一定范围内实现大致均匀的分布。

为了保持压实 cell 中的机器异构性,我们随机选择要移除的主机。为了保持工作负载的异构性,我们保留了除特定机器(例如 Borglets) 相关的服务器和存储 tasks。对于大于原始 cell 大小一半的 jobs,我们将硬约束更改为软约束,如果它们非常"挑剔"并且只能调度在少数主机上,则允许 0.2% 的 tasks 处于等待状态。大量实验表明,这以很小的方差产生了可重复的结果。如果我们需要比原来更大的 cell,则在压实前多克隆原始 cell 几次;如果需要更多的 cells,我们只从原始 cell 克隆。

针对每个 cell 和不同随机数种子,每个实验重复 11 次。在图中,我们使用误差条显示所需机器数量的最小值和最大值,并选择 90%ile 值作为“结果” - 如果系统管理员想合理确定 workload 能否放得下,平均值和中位数并不能反映他应该怎么做。我们认为 cell compaction 提供了一种公平一致的方式来比较调度策略,并且可以直接转换为成本/收益结果:更好的策略需要更少的机器来运行相同的 workload。

我们的实验侧重于从某个时间点调度(打包)工作负载,而不是重放长期工作负载跟踪。一部分原因是为了避免应对打开和关闭队列模型困难,一部分是因为传统的完成时间指标不适用于我们的环境以及长期运行的服务,一部分是为了压实提供一个干净的信号,一部分是我们不相信结果会有显著差异,以及一部分实际问题:我们发现自己在某一时刻因为我们的实验消耗了 200000 Borg CPU 内核 – 即使在 Google 这个规模上,这也是一项非常大的投资。

在生产中,我们会故意为 workload 增长、偶发的“黑天鹅”事件、负载峰值、机器故障、硬件升级以及大规模局部故障(如供电母线槽故障)留下显著余量。图 4 展示了如果对真实世界的 cells 应用 cell compaction,它们可以缩小多少。

borg-compacted-size.png

6.2. Cell sharing

我们几乎所有的机器同时运行生产和非生产的 tasks:98% 的主机在共享 Borg cells 中,在 Borg 管理的整套机器中占 83%。(我们有一些特殊用途的专用 cells)

由于许多其他组织会在独立集群中运行面向用户的 jobs 和批处理 jobs,我们审查了如果我们也这样做会发生什么。图 5 显示,在中位数 cell 中,分离生产和非生产工作需要额外 20-30% 的机器来运行我们的 workload。这是因为生产 jobs 通常会预留资源来处理罕见的工作负载峰值,但大多数时候并不使用这些资源。Borg 会回收未使用的资源来运行大部分非生产工作,因此我们总体上需要更少的机器。

borg-prod-noprod-different-cells.png

大多数 Borg cells 由数千个用户共享。图 6 展示了原因。对于这些测试,针对需要至少 10TiB 的内存(或 100TiB)的用户,我们将用户的工作负载分成新的 cell。我们现有的政策看起来很好:即使门槛较大,我们也需要 2-16 倍的 cells,以及 20-150% 的额外机器。再次强调,汇集资源可以显著降低成本。

borg-user-different-cells.png

但是,将不相关的用户和 job 类型打包到同一台主机会导致 CPU 竞争,因此我们需要更多的机器来补偿?为了评估这一点,我们研究了在具有相同时钟速度的相同机器类型下运行不同环境中的 CPI(每条指令的周期)如何变化。在这些条件下,CPI 值具有可比性,可用作性能干扰的一个代理,因为 CPI 加倍会使 CPU 绑定程序的运行时间加倍。数据是一周内从大约 12000 个随机选择的生产 tasks 中收集的,使用83 中描述的硬件配置基础设施计算 5 分钟间隔内的周期和指令,并对样本进行加权,以便每秒计算 CPU 时间。结果并不明确。

  • 我们发现 CPI 与同一时间间隔内的两次测量正相关:机器上的总体 CPU 使用率,以及(很大程度上独立地)机器上的任务数量;向机器添加 task 会使其它 tasks 的 CPI 增加 0.3%(使用适合数据的线性模型);将机器 CPU 使用率提高 10% 会使 CPI 增加不到 2%。但即使相关性具有显著性,它们也只解释了我们在 CPI 测量中看到的 5% 的方差;其它因素占主导地位,例如应用和特定干扰模式的固有差异24,83
  • 将我们从共享 cells 中采样的 CPI 与应用种类较少的专用 cells 比较,我们看到共享 cells 的平均 CPI 为 1.58(σ = 0.35),专用 cells 的平均 CPI 为 1.53(σ = 0.32)– 即,共享 cells 中的 CPU 性能差大约 3%。
  • 为了解决应用在不同 cells 中可能有不同的 workload,甚至可能存在选择偏差(也许对干扰更敏感的程序已经被移入专用 cells)的担忧,我们查看了 Borglet 的 CPI,它会在两种类型 cells 的所有机器上运行。我们发现它在专用 cells 中的 CPI 为 1.20(σ = 0.29),在共享 cells 中的 CPI 为 1.43(σ = 0.45),这表明它在专用 cell 中的运行速度是在共享 cell 中的 1.19 倍,尽管这会过度放大轻负载机器的影响,使结果稍微偏向于专用 cells。

这些实验证实,仓库规模的性能比较是棘手的,加强了51 中的观察,并且表明共享并不会大幅度增加程序运行的成本。

但即使我们假设我们的结果最不利,共享仍然是占优的:由于几种不同分区方案所需要的机器减少,CPU 减速不再受到影响,共享优势适用于所有资源,包括内存和磁盘,而不仅仅是 CPU。

6.3. Large cells

Google 构建了大型 cells,既允许运行大型计算,又可以减少资源碎片。我们通过在多个较小的 cells 中划分 cell 的工作负载来测试后者的影响 - 首先随机置换 jobs 并在分区间以循环方式分配它们。图 7 证实使用较小的 cells 需要更多的机器。

borg-small-cells-more-machines.png

6.4. Fine-grained resource requests

Borg 用户以 milli-core(千分之一核)为单位请求 CPU,以 bytes(字节)为单位请求内存和磁盘空间。(一个 core 是处理器超线程,并按不同机器类型的性能做了标准化。)图 8 显示了它们确实利用了这种粒度:请求的内存或 CPU 核数量中几乎没有明显的“甜点”,并且在这些资源间几乎没有明显的相关性。这些分布与68 中的分布非常相似,除了我们看到 90%ile 以及以上的内存请求略大。

borg-cdf-cpu-memory.png

提供一组固定大小的容器或者虚拟机,虽然在 IaaS(基础设施即服务)提供商中很常见,但并不能很好地满足我们的需求。为了证明这一点,我们把生产 jobs 和 allocs 的 CPU 核与内存资源限制“分桶”,也就是在每个资源维度上向上取整到最接近的 2 的幂,CPU 从 0.5core 开始,内存从 1GiB 开始。图 9 显示,这样做在中位数情况下需要额外 30%~50% 的资源。上限来自在压缩开始前把原始 cell 扩大四倍之后,仍需要把整台机器分配给无法放入的大型 tasks;下限来自允许这些 tasks 进入 pending。(这比37 报告的大约 100% overhead 要少,因为我们支持超过 4 个 buckets,并允许 CPU 和内存容量独立扩展。)

borg-cdf-add-overheads.png

6.5. Resource reclamation

一个 job 可以指定资源 limit,也就是每个 task 应该获得的资源上限。Borg 使用这个 limit 来确定用户是否有足够的配额准入这个 job,并确定特定机器是否有足够的空闲资源来调度这个 task。正如有些用户会购买超过实际需要的配额一样,有些用户请求的资源也比 tasks 实际会使用的资源更多,因为 Borg 通常会杀死尝试使用超过请求值的内存或磁盘空间的 task,或者把 CPU 限制在其请求值内。此外,某些 tasks 偶尔需要使用其全部资源(例如,在一天的高峰时段或应对拒绝服务攻击时),但大多数情况下并不会。

与其浪费当前未被消耗的已分配资源,我们会估计一个 task 将使用多少资源,并把剩余资源回收给可以容忍较低质量资源的工作,例如批处理 jobs。整个过程称为资源回收。这个估计值称为 task 的 reservation,并由 Borgmaster 每隔几秒使用 Borglet 捕获的细粒度使用(资源消耗)信息计算。初始 reservation 设置为等于资源请求(limit);在 300 秒之后,为了留出启动瞬态时间,它会朝着实际使用量加安全余量缓慢衰减。如果使用量超过 reservation,则 reservation 会迅速增加。

Borg 调度器使用 limits 来计算生产 tasks 的可行性,因此它们从不依赖回收资源,也不会暴露在资源超订中;对于非生产 tasks,它使用现有 tasks 的 reservations,因此可以把新的 tasks 调度到回收资源中。

如果预留(预测)错误,机器可能会在运行时耗尽资源 - 即使所有 tasks 的使用都低于其限制。如果发生这种情况,我们会杀死或限制非生产 tasks,从来不针对生产 tasks。

图 10 显示了如果没有资源回收会需要多得多的机器。大约 20% 的 workload 在中位数 cell 中运行在回收资源上。

borg-cdf-additional-machines.png

我们可以从图 11 中看到更多的细节,其中显示了预留和使用与限制的比率。超出其内存限制的 task 将是第一个在需要资源时被抢占的 task,无论其优先级如何,因此在 tasks 超出其内存资源限制的情况下比较少见。另一方面,CPU 可以很容易地被限制,因此短期峰值可以相当无害地推动使用超出预留。

borg-cdf-ratio-cpu-mem.png

图 12 显示了发生的事情。第二周 reservations 明显更接近使用量,第三周也有一定接近,而基线周(第 1 周和第 4 周)显示出最大差距。正如预期的那样,内存 OOM 事件的发生率在第 2 周和第 3 周略有增加。在审查这些结果后,我们认为净收益超过了负面影响,并将中等资源回收参数部署到其它 cells。

borg-oom-events.png

7. Isolation

我们 50% 的机器运行 9 个或更多 tasks;90%ile 机器大约运行 25 个 tasks 并将运行 4500 个线程83。尽管在应用程序之间共享机器可以提高利用率,但它还需要良好的机制来防止 tasks 之间互相干扰。这适用于安全性和性能。

7.1. Security isolation

我们使用 Linux chroot jail 作为同一台机器上多个 tasks 之间的主要安全隔离机制。为了允许远程调试,我们过去会自动分发(和撤销)ssh 密钥,以便用户只有在机器运行该用户的 tasks 时才能访问这台机器。对大多数用户来说,这已经被 borgssh 命令取代;该命令会与 Borglet 协作构建一个到 shell 的 ssh 连接,这个 shell 与 task 运行在相同的 chroot 和 cgroup 中,从而更严格地锁定访问权限。

VM 和安全沙箱技术用于运行 Google 的 AppEngine(GAE)38 和 Google Compute Engine(GCE)的外部软件。我们在运行每个托管 VM 的 KVM 进程54 中运行 Borg task。

7.2. Performance isolation

Borglet 的早期版本具有原始的资源隔离:对内存、磁盘空间和 CPU 周期性进行事后检查,结合终止使用过多内存或磁盘的 tasks 以及积极应用 Linux 的优先级来控制使用 CPU 太多的 tasks。但是,流氓 tasks 太容易影响机器上其它 tasks 的性能,因此一些用户夸大他们的资源请求,以减少 Borg 可以与他们共同调度的 tasks 数量,从而降低利用率。由于所涉及的安全边际,资源回收可能会收回部分盈余,但不是全部。在最极端的情况下,用户请求使用专用机器或 cell。

现在,所有的 Borg tasks 运行在一个基于 Linux cgroup 的资源容器中17,58,62,并且 Borglet 会操作容器设置;因为操作系统内核参与其中,控制能力得到了很大改善。即使如此,偶发的低层资源干扰(例如内存带宽或 L3 高速缓存污染)仍然会发生,如60,83

为了帮助处理过载和超配,Borg tasks 有一个 application class 或 appclass。最重要的区别在于延迟敏感(LS)appclasses 和其它 appclasses,本文中将后者称为批处理。LS tasks 用于需要快速响应请求的面向用户的应用程序和共享基础设施服务。高优先级 LS tasks 获得最佳处理,并且可以一次让批处理 tasks 暂时饿死几秒钟。

第二个划分是在可压缩资源和不可压缩资源之间。可压缩资源(如 CPU 周期、磁盘 I/O 带宽)是基于速率的,可以通过降低服务质量从 task 中回收,而不必杀死 task;不可压缩资源(如内存、磁盘空间)通常不杀死 task 就无法回收。如果机器耗尽了不可压缩资源,Borglet 会立即从最低优先级到最高优先级终止 tasks,直到可以满足剩余的 reservations。如果机器耗尽了可压缩资源,Borglet 会限制使用(支持 LS tasks),以便在不中断任何 tasks 的情况下处理短负载峰值。如果事情没有改善,Borgmaster 将从机器中删除一个或者多个 tasks。

Borglet 中的用户空间控制循环会根据预测的未来使用(针对生产 tasks)或者内存压力(针对非生产 tasks)为容器分配内存;处理来自内核的 OOM 事件;并且当 tasks 尝试分配超过内存限制时,或者当一台超配机器实际耗尽内存时杀死它们。由于需要精确的内存统计,Linux 的 eager file-caching 会显著增加实现复杂度。

为了提高性能隔离,LS tasks 可以保留整个物理 CPU 核,从而阻止其它 LS tasks 使用它们。批处理 tasks 允许在任何核上运行,但是相对于 LS tasks,它们只获得很小的调度器 share。Borglet 会动态调整贪婪 LS tasks 的资源上限,以确保它们不会让批处理 tasks 持续饿死数分钟,并在需要时选择性地应用 CFS 带宽控制75;仅靠 shares 不够,因为我们有多个优先级级别。

和 Leverich56 一样,我们发现标准 Linux CPU 调度器(CFS)需要进行大量调整以同时支持低延迟和高利用率。为了减少调度延迟,我们的 CFS 版本使用扩展的 per-cgroup 负载历史16,允许 LS tasks 抢占批处理 tasks,并在多个 LS tasks 可在 CPU 上运行时减少调度时间片。幸运的是,我们的许多应用程序都使用 thread-per-request 模型,这可以减轻持续负载不平衡的影响。我们谨慎使用 cpusets 将 CPU 内核分配给具有特别严格延迟要求的应用程序。这些努力的一些结果如图 13 所示。该领域的工作仍在继续,正在增加能够感知 NUMA、超线程和功耗的线程放置与 CPU 管理(例如81),并提高 Borglet 的控制精度。

borg-cpu-util.png

Tasks 被允许消耗资源直到其 limit。大多数 tasks 被允许在 CPU 等可压缩资源上超过 limit,以利用未使用的(slack)资源。只有 5% 的 LS tasks 会禁用此功能,可能是为了获得更好的可预测性;不到 1% 的批处理 tasks 这样做。默认情况下禁用使用 slack 内存,因为它会增加 tasks 被杀的可能性,但即便如此,10% 的 LS tasks 会覆盖这个设置,79% 的批处理 tasks 也会这样做,因为这是 MapReduce 框架的默认设置。这补充了回收资源的结果。批处理 tasks 愿意机会性利用未使用以及已回收的内存:大多数时候这是有效的,尽管当 LS tasks 急需资源时,偶尔会牺牲批处理 tasks。

8. Related work

资源调度已经研究了数十年,其中包括广域 HPC 超级计算网格,工作站网格和大规模服务器集群等各种环境。我们只关注大规模服务器集群环境中最相关的工作。

最近的几项研究分析了雅虎、谷歌和 Facebook 的集群痕迹20,52,63,68,70,80,82,并说明这些现代数据中心和工作负载所固有的规模和异构性的挑战。69 包含集群管理器体系结构的分类。

Apache Mesos45 使用 offer-based 机制,在一个中心资源管理器(有点类似去掉调度器的 Borgmaster)和多个 "frameworks"(如 Hadoop41 和 Spark73)之间拆分资源管理和放置功能。Borg 主要使用基于请求的机制集中这些功能,这种机制可以很好地扩展。DRF29,35,36,66 最初是为 Mesos 开发的;Borg 则使用优先级和准入配额。Mesos 开发人员已宣布计划扩展 Mesos,使其包括推测性资源分配和回收,并修复69 中指出的一些问题。

YARN76 是一个以 Hadoop 为中心的集群管理器。每个应用程序都有一个 manager,通过中央资源管理器协商所需要的资源;这与 Google MapReduce jobs 从 2008 年左右开始用于从 Borg 获取资源的方案大致相同。YARN 的资源管理器最近才变得容错。一个相关的开源工作是 Hadoop Capacity Scheduler42,它提供多租户支持,包括容量保证、分层队列、弹性共享和公平性。YARN 最近已经扩展到支持多种资源类型、优先级、抢占和高级准入控制21。Tetris 研究原型40 支持 makespan-aware job packing。

Facebook 的 Tupperware64 是一个类似 Borg 的系统,用于集群上的 cgroup 容器;虽然它似乎提供了一种资源回收形式,但只披露了一些细节。Twitter 有开源的 Aurora5,一个类似 Borg 的调度程序,用于运行在 Mesos 之上的长期运行服务,配置语言和状态机类似于 Borg。

Microsoft 的 Autopilot 系统48 为 Microsoft clusters 提供“自动化软件制备和部署;系统监控;以及执行修复操作以处理有故障的软件和硬件”。Borg 生态系统提供了类似的功能,但篇幅所限这里不再讨论;Isaard48 概述了我们同样遵循的许多最佳实践。

Quincy49 使用网络流模型为数百个节点集群上的数据处理 DAG 提供公平性和数据位置感知调度。Borg 使用配额和优先级来共享用户之间的资源,并扩展到数万台计算机。Quincy 直接处理执行图,而这是在 Borg 之上单独构建的。

Cosmos44 专注于批处理,重点是确保用户能够公平地访问他们贡献给集群的资源。它使用 per-job manager 来获取资源;公开的细节很少。

微软的 Apollo 系统13 使用 per-job 调度器处理短生命周期批处理 jobs,以便在规模看起来与 Borg cells 相当的集群上实现高吞吐量。Apollo 使用低优先级后台工作的机会性执行,以(有时)多天排队延迟为代价将利用率提高到高水平。Apollo 节点会提供一个任务开始时间预测矩阵,该矩阵是任务在两个资源维度上大小的函数;调度器会将它与启动成本和远程数据访问的估计相结合,以进行放置决策,并通过随机延迟调节以减少冲突。Borg 使用中央调度器,根据先前分配的状态做放置决策,可以处理更多资源维度,并专注于高可用、长期运行应用程序的需求;Apollo 可能可以处理更高的 task 到达率。

Alibaba 的伏羲84 支持数据分析工作量;它自 2009 以来一直在运行。与 Borgmaster 一样,FuxiMaster(为故障容忍而复制)从节点收集资源可用性信息,接受来自应用程序的请求,并将其匹配。伏羲增量调度策略与 Borg 的等价类相反:伏羲不是将每个任务与一组合适的机器匹配,而是将新可用资源与待处理工作的积压相匹配。与 Mesos 一样,伏羲允许定义 "虚拟资源" 类型。只有合成工作负载结果可公开获得。

Omega69 支持多个并行、专门化的 "verticals",每个 vertical 大致相当于一个去掉持久化存储和链接分片的 Borgmaster。Omega 调度器使用乐观并发控制来操作一个共享表示,该表示包含期望和观察到的 cell 状态,存储在中央持久化存储中,并通过单独的 link component 与 Borglets 双向同步。Omega 架构旨在支持多个不同的 workloads,这些 workloads 拥有自己的应用专用 RPC 接口、状态机和调度策略(例如,长时间运行的服务、来自各种框架的批处理 jobs、类似集群存储系统的基础设施服务、来自 Google Cloud Platform 的虚拟机)。另一方面,Borg 提供了 "one size fits all" 的 RPC 接口、状态机语义和调度策略;由于需要支持许多不同 workloads,其规模和复杂性随着时间推移而增长,但可扩展性尚未成为问题。

Google 开源 Kubernetes 系统53 将运行在 Docker 容器28 中的应用放置到多个主机节点上。它既可以在裸机(如 Borg)上运行,也可以在各种云托管服务提供商上运行,例如 Google Compute Engine。许多构建 Borg 的工程师正在积极开发它。Google 提供了一个名为 Google Container Engine 的托管版本39。我们将在下一节讨论如何将 Borg 的经验教训应用于 Kubernetes。

高性能计算社区在该领域有着悠久的工作传统(例如 Maui、Moab、Platform LSF2,47,50);但是,规模、workloads 以及容错要求与 Google 的 cells 不同。通常,这样的系统通过大量 pending 工作积压(队列)来实现高利用率。

VMware77 等虚拟化提供商,以及 HP 和 IBM46 等数据中心解决方案提供商,提供的集群管理解决方案通常可扩展到 O(1000) 台机器。此外,一些研究小组已经构建了原型系统,以某种方式提高调度决策质量(例如25,40,72,74)。

最后,正如我们所指出的,管理大规模集群的另外一个重要组成部分是自动化和 "operator scaleout"。43 描述了为故障、多租户、健康检查、准入控制和可重启性做规划,是实现每个 operator 管理大量机器所必需的。Borg 的设计理念类似,允许我们支持每个 operator(SRE)管理数万台机器。

9. Lessons and future work

在本节中,我们将重述 Borg 运行在生产环境十多年来的一些经验教训,并描述这些观察结果如何在设计 Kubernetes 时得到应用。

9.1. Lessons learned: the bad

我们从 Borg 的一些特征开始,作为警示故事,并在 Kubernetes 中提供有根据的替代设计。

Job 作为唯一的 tasks 分组机制,是有限制的。 Borg 没有一等方式将整个 multi-job 服务作为单个实体进行管理,或者引用某个服务的相关实例(例如 canary 和 production tracks)。作为一种 hack,用户会在 job 名称中编码服务拓扑,并构建更高级别的管理工具来解析这些名字。另一方面,也不能引用 job 的任意子集,这会导致滚动更新和 job 大小调整等语义不灵活的问题。为了避免这种困难,Kubernetes 摒弃了 job 概念,而是通过 labels 来组织调度单元(pods)- 用户可以将任意 key/value 对附加到系统中的任何对象。等价于 Borg 的一个 job,可以通过将 job:jobname 标签关联到一组 pods 实现,也可以表示任何其它有用的分组,例如 service、tier 或者 release-type(如 production、staging、test)。Kubernetes 中的操作通过标签查询来识别其目标对象并应用操作。这种方式比单个固定的 job 分组更灵活。

每个主机一个 IP 地址带来复杂性。 在 Borg,主机上的所有 task 都使用其主机的单个 IP 地址,从而共享主机的端口空间。这会导致很多麻烦:Borg 必须将端口作为资源,tasks 必须预先声明它们需要多少端口,并且声明在启动时使用哪些端口;Borglet 必须强制执行端口隔离;以及命名和 RPC 系统必须像对待 IP 地址一样处理端口。

由于 Linux 命名空间,VMs,IPv6,以及软件定义网络的出现,Kubernetes 可以采用对用户更加友好的方式,来消除这些复杂性:每个 pod 和 service 都有自己的 IP 地址,允许开发人员选择端口而不是要求他们的软件适配基础设施,并消除了端口管理的基础架构复杂性。

为了高级用户而优化,以牺牲普通用户为代价。 Borg 提供了一系列针对 "power users" 的功能,使他们可以微调程序的运行方式(BCL 规范列出了大约 230 个参数):最初的焦点是支持 Google 最大的资源消费者,对他们来说效率提升至关重要。不幸的是,这种 API 的丰富性使得 "casual" 用户更难使用,并限制了它的发展。我们的解决方案是在 Borg 之上构建自动化工具和服务,并通过实验确定适当的设置。这些工具可以从容错应用提供的实验自由度中获益:如果自动化出错,那只是麻烦,而不是灾难。

9.2. Lessons learned: the good

另一方面,Borg 的一些设计特性非常有益,并经受住了时间考验。

Allocs 非常有用。 Borg alloc 抽象催生了广泛使用的 logsaver 模式,以及另一种流行模式:由一个简单的数据加载器 task 定期更新 Web server 使用的数据。Allocs 和 packages 允许这样的 helper 服务由不同团队开发。Kubernetes 中等效于 alloc 的概念是 pod,它是一个或多个容器的资源包,这些容器始终被调度到同一台机器上并可以共享资源。Kubernetes 使用同一个 pod 中的 helper 容器,而不是 alloc 中的 tasks,但思路是一样的。

集群管理不仅仅是 task 管理。 虽然 Borg 的主要职责是管理 tasks 和主机的生命周期,但在 Borg 上运行的应用程序可以从许多其它集群服务中受益,包括命名和负载均衡。Kubernetes 通过 service 抽象支持命名和负载均衡:一个 service 有一个名字和一个通过标签选择器的动态 pod 集。集群中的任何一个容器都可以通过 service 名来访问服务。在这一层上,Kubernetes 会自动对和标签选择器匹配的 pod 之间的服务连接进行负载均衡,并跟踪由于故障而重新调度的 pod。

自我检查是至关重要的。 虽然 Borg 几乎总是 "正常工作",但当出现问题时,找到根因可能是很具挑战性的。Borg 的一个重要设计决策是向所有用户显示调试信息而不是隐藏它:Borg 拥有数千名用户,因此 "自助" 必须是调试的第一步。尽管这使得我们更难以弃用功能并改变用户所依赖的内部策略,但是它仍然是一个胜利,我们发现实际没有选择的余地。为了处理庞大的数据,我们提供了多个级别的 UI 和调试工具,因此用户可以快速识别与其 jobs 相关的异常事件,然后深入查看其应用程序和基础架构本身的详细数据和错误日志。

Kubernetes 旨在复制 Borg 的许多自我检查技术。例如,它附带了用于资源监控的 cAdvisor15 工具,以及基于 Elasticsearch/Kibana30 和 Fluentd32 的日志聚合。可以查询主服务器以获取其对象状态的快照。Kubernetes 有一个统一的机制,所有组件都可以用来记录事件(例如,正在调度的容器,失败的容器)以提供给客户。

master 是分布式系统的内核。 Borgmaster 最初被设计为一个单体系统,但是随着时间推移,它变得更像一个内核,位于协作管理用户 jobs 的服务生态系统的核心。例如,我们将调度器和主 UI(Sigma)拆分为单独进程,并添加了用于准入控制、垂直和水平自动扩展、重新打包 tasks、周期性 job 提交(cron)、工作流管理以及归档系统行为以供离线查询的服务。

Kubernetes 架构进一步采用了这种思路:它的核心拥有一个 API server,只负责处理请求和操作底层状态对象。集群管理逻辑则构建为这个 API server 客户端的一组小型、可组合 micro-services,例如复制控制器,它可以在出现故障时维护 pod 所需的副本数量,以及节点控制器,它管理机器生命周期。

9.3. Conclusion

实际上,Google 的所有集群工作负载在过去十年中都转向使用 Borg。我们会继续发展它,并将我们从中学到的经验应用到 Kubernetes。

10. References

[2] Adaptive Computing Enterprises Inc., Provo, UT. Maui Scheduler Administrator’s Guide, 3.2 edition, 2011.

[5] Apache Aurora. http://aurora.incubator.apache.org/, 2014.

[13] E. Boutin, J. Ekanayake, W. Lin, B. Shi, J. Zhou, Z. Qian, M. Wu, and L. Zhou. Apollo: scalable and coordinated scheduling for cloud-scale computing. In Proc. USENIX Symp. on Operating Systems Design and Implementation (OSDI), Oct. 2014.

[15] cAdvisor. https://github.com/google/cadvisor, 2014.

[16] CFS per-entity load patches. http://lwn.net/Articles/531853, 2013.

[17] cgroups. http://en.wikipedia.org/wiki/Cgroups, 2014.

[20] Y. Chen, S. Alspaugh, and R. H. Katz. Design insights for MapReduce from diverse production workloads. Technical Report UCB/EECS-2012-17, UC Berkeley, Jan. 2012.

[21] C. Curino, D. E. Difallah, C. Douglas, S. Krishnan, R. Ramakrishnan, and S. Rao. Reservation-based scheduling: if you’re late don’t blame us! In Proc. ACM Symp. on Cloud Computing (SoCC), pages 2:1-2:14, Seattle, WA, USA, 2014.

[24] C. Delimitrou and C. Kozyrakis. Paragon: QoS-aware scheduling for heterogeneous datacenters. In Proc. Int’l Conf. on Architectural Support for Programming Languages and Operating Systems (ASPLOS), Mar. 2013.

[25] C. Delimitrou and C. Kozyrakis. Quasar: resource-efficient and QoS-aware cluster management. In Proc. Int’l Conf. on Architectural Support for Programming Languages and Operating Systems (ASPLOS), pages 127-144, Salt Lake City, UT, USA, 2014.

[28] Docker Project. https://www.docker.io/, 2014.

[29] D. Dolev, D. G. Feitelson, J. Y. Halpern, R. Kupferman, and N. Linial. No justified complaints: on fair sharing of multiple resources. In Proc. Innovations in Theoretical Computer Science (ITCS), pages 68-75, Cambridge, MA, USA, 2012.

[30] ElasticSearch. http://www.elasticsearch.org, 2014.

[32] Fluentd. http://www.fluentd.org/, 2014.

[35] A. Ghodsi, M. Zaharia, B. Hindman, A. Konwinski, S. Shenker, and I. Stoica. Dominant Resource Fairness: fair allocation of multiple resource types. In Proc. USENIX Symp. on Networked Systems Design and Implementation (NSDI), pages 323-326, 2011.

[36] A. Ghodsi, M. Zaharia, S. Shenker, and I. Stoica. Choosy: max-min fair sharing for datacenter jobs with constraints. In Proc. European Conf. on Computer Systems (EuroSys), pages 365-378, Prague, Czech Republic, 2013.

[37] D. Gmach, J. Rolia, and L. Cherkasova. Selling T-shirts and time shares in the cloud. In Proc. IEEE/ACM Int’l Symp. on Cluster, Cloud and Grid Computing (CCGrid), pages 539-546, Ottawa, Canada, 2012.

[38] Google App Engine. http://cloud.google.com/AppEngine, 2014.

[39] Google Container Engine (GKE). https://cloud.google.com/container-engine/, 2015.

[40] R. Grandl, G. Ananthanarayanan, S. Kandula, S. Rao, and A. Akella. Multi-resource packing for cluster schedulers. In Proc. ACM SIGCOMM, Aug. 2014.

[41] Apache Hadoop Project. http://hadoop.apache.org/, 2009.

[42] Hadoop MapReduce Next Generation - Capacity Scheduler. http://hadoop.apache.org/docs/r2.2.0/hadoop-yarn/hadoop-yarn-site/CapacityScheduler.html, 2013.

[43] J. Hamilton. On designing and deploying internet-scale services. In Proc. Large Installation System Administration Conf. (LISA), pages 231-242, Dallas, TX, USA, Nov. 2007.

[44] P. Helland. Cosmos: big data and big challenges. http://research.microsoft.com/en-us/events/fs2011/helland_cosmos_big_data_and_big_challenges.pdf, 2011.

[45] B. Hindman, A. Konwinski, M. Zaharia, A. Ghodsi, A. Joseph, R. Katz, S. Shenker, and I. Stoica. Mesos: a platform for fine-grained resource sharing in the data center. In Proc. USENIX Symp. on Networked Systems Design and Implementation (NSDI), 2011.

[46] IBM Platform Computing. http://www-03.ibm.com/systems/technicalcomputing/platformcomputing/products/clustermanager/index.html.

[47] S. Iqbal, R. Gupta, and Y.-C. Fang. Planning considerations for job scheduling in HPC clusters. Dell Power Solutions, Feb. 2005.

[48] M. Isaard. Autopilot: Automatic data center management. ACM SIGOPS Operating Systems Review, 41(2), 2007.

[49] M. Isard, V. Prabhakaran, J. Currey, U. Wieder, K. Talwar, and A. Goldberg. Quincy: fair scheduling for distributed computing clusters. In Proc. ACM Symp. on Operating Systems Principles (SOSP), 2009.

[50] D. B. Jackson, Q. Snell, and M. J. Clement. Core algorithms of the Maui scheduler. In Proc. Int’l Workshop on Job Scheduling Strategies for Parallel Processing, pages 87-102. Springer-Verlag, 2001.

[51] M. Kambadur, T. Moseley, R. Hank, and M. A. Kim. Measuring interference between live datacenter applications. In Proc. Int’l Conf. for High Performance Computing, Networking, Storage and Analysis (SC), Salt Lake City, UT, Nov. 2012.

[52] S. Kavulya, J. Tan, R. Gandhi, and P. Narasimhan. An analysis of traces from a production MapReduce cluster. In Proc. IEEE/ACM Int’l Symp. on Cluster, Cloud and Grid Computing (CCGrid), pages 94-103, 2010.

[53] Kubernetes. http://kubernetes.io, Aug. 2014.

[54] Kernel Based Virtual Machine. http://www.linux-kvm.org.

[56] J. Leverich and C. Kozyrakis. Reconciling high server utilization and sub-millisecond quality-of-service. In Proc. European Conf. on Computer Systems (EuroSys), page 4, 2014.

[58] Google LMCTFY project (let me contain that for you). http://github.com/google/lmctfy, 2014.

[60] J. Mars, L. Tang, R. Hundt, K. Skadron, and M. L. Soffa. Bubble-Up: increasing utilization in modern warehouse scale computers via sensible co-locations. In Proc. Int’l Symp. on Microarchitecture (Micro), Porto Alegre, Brazil, 2011.

[62] P. Menage. Linux control groups. http://www.kernel.org/doc/Documentation/cgroups/cgroups.txt, 2007-2014.

[63] A. K. Mishra, J. L. Hellerstein, W. Cirne, and C. R. Das. Towards characterizing cloud backend workloads: insights from Google compute clusters. ACM SIGMETRICS Performance Evaluation Review, 37:34-41, Mar. 2010.

[64] A. Narayanan. Tupperware: containerized deployment at Facebook. http://www.slideshare.net/dotCloud/tupperware-containerized-deployment-at-facebook, June 2014.

[66] D. C. Parkes, A. D. Procaccia, and N. Shah. Beyond Dominant Resource Fairness: extensions, limitations, and indivisibilities. In Proc. Electronic Commerce, pages 808-825, Valencia, Spain, 2012.

[68] C. Reiss, A. Tumanov, G. Ganger, R. Katz, and M. Kozuch. Heterogeneity and dynamicity of clouds at scale: Google trace analysis. In Proc. ACM Symp. on Cloud Computing (SoCC), San Jose, CA, USA, Oct. 2012.

[69] M. Schwarzkopf, A. Konwinski, M. Abd-El-Malek, and J. Wilkes. Omega: flexible, scalable schedulers for large compute clusters. In Proc. European Conf. on Computer Systems (EuroSys), Prague, Czech Republic, 2013.

[70] B. Sharma, V. Chudnovsky, J. L. Hellerstein, R. Rifaat, and C. R. Das. Modeling and synthesizing task placement constraints in Google compute clusters. In Proc. ACM Symp. on Cloud Computing (SoCC), pages 3:1-3:14, Cascais, Portugal, Oct. 2011.

[72] A. Singh, M. Korupolu, and D. Mohapatra. Server-storage virtualization: integration and load balancing in data centers. In Proc. Int’l Conf. for High Performance Computing, Networking, Storage and Analysis (SC), pages 53:1-53:12, Austin, TX, USA, 2008.

[73] Apache Spark Project. http://spark.apache.org/, 2014.

[74] A. Tumanov, J. Cipar, M. A. Kozuch, and G. R. Ganger. Alsched: algebraic scheduling of mixed workloads in heterogeneous clouds. In Proc. ACM Symp. on Cloud Computing (SoCC), San Jose, CA, USA, Oct. 2012.

[75] P. Turner, B. Rao, and N. Rao. CPU bandwidth control for CFS. In Proc. Linux Symposium, pages 245-254, July 2010.

[76] V. K. Vavilapalli, A. C. Murthy, C. Douglas, S. Agarwal, M. Konar, R. Evans, T. Graves, J. Lowe, H. Shah, S. Seth, B. Saha, C. Curino, O. O’Malley, S. Radia, B. Reed, and E. Baldeschwieler. Apache Hadoop YARN: Yet Another Resource Negotiator. In Proc. ACM Symp. on Cloud Computing (SoCC), Santa Clara, CA, USA, 2013.

[77] VMware VCloud Suite. http://www.vmware.com/products/vcloud-suite/.

[80] J. Wilkes. More Google cluster data. http://googleresearch.blogspot.com/2011/11/more-google-cluster-data.html, Nov. 2011.

[81] Y. Zhai, X. Zhang, S. Eranian, L. Tang, and J. Mars. HaPPy: Hyperthread-aware power profiling dynamically. In Proc. USENIX Annual Technical Conf. (USENIX ATC), pages 211-217, Philadelphia, PA, USA, June 2014. USENIX Association.

[82] Q. Zhang, J. Hellerstein, and R. Boutaba. Characterizing task usage shapes in Google’s compute clusters. In Proc. Int’l Workshop on Large-Scale Distributed Systems and Middleware (LADIS), 2011.

[83] X. Zhang, E. Tune, R. Hagmann, R. Jnagal, V. Gokhale, and J. Wilkes. CPI2: CPU performance isolation for shared compute clusters. In Proc. European Conf. on Computer Systems (EuroSys), Prague, Czech Republic, 2013.

[84] Z. Zhang, C. Li, Y. Tao, R. Yang, H. Tang, and J. Xu. Fuxi: a fault-tolerant resource management and job scheduling system at internet scale. In Proc. Int’l Conf. on Very Large Data Bases (VLDB), pages 1393-1404. VLDB Endowment Inc., Sept. 2014.

Kumu2018-12-23 Sun 00:00Emacs 30.2 (Org mode 9.7.11)