共计 6849 个字符,预计需要花费 18 分钟才能阅读完成。
本篇内容介绍了“Borg 使用策略是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让丸趣 TV 小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
使用效率
Borg 的一个主要目的就是有效的利用 Google 的机器舰队,这可是一大笔财务投资:让效率提升几个百分点就能省下几百万美元。
1 测度方法论
我们的 job 部署是有资源约束的,而且很少碰到负载高峰,我们的机器是异构的,我们从 service job 回收利用的资源跑 batch job。所以,为了测量我们需要一个比“平均利用率”更抽象的标准。在做了一些实验后我们选择了 cell 密度(cell compaction):给定一个负载,我们不断的从零开始(这样可以避免被一个倒霉的配置卡住),部署到尽可能小的 Cell 里面去,直到再也不能从这个 cell 里面抽机器出来。这提供了一个清晰的终止条件,并促进了无陷阱的自动化比较,这里的陷阱指的是综合化的工作负载和建模[31]。一个定量的比较和估算技术可以看[78],有不少微妙的细节。
我们不可能在线上的 cell 做性能实验,所以我们用了 Fauxmaster 来达到高保真的模拟效果,使用了真的在线 cell 的负载数据包括所有的约束、实际限制、保留和常用数据 ($5.5)。这些数据从 2014-10-1 14:00 PDT 的 Borg 快照(checkpoints) 里面提取出来。(其他快照也产生类似的结论)。我们选取了 15 个 Borg cell 来出报告,先排除了特殊目的的、测试的、小的 (5000 机器) 的 cell,然后从剩下的各种量级大小的 cell 中平均取样。
在压缩 cell 实验中为了保持机器异构性,我们随机选择去掉的机器。为了保持工作负载的异构性,我们保留了所有负载,除了那些对服务和存储需要有特定需求的。我们把那些需要超过一半 cell 的 job 的硬限制改成软的,允许不超过 0.2% 的 task 持续的 pending 如果它们过于挑剔机器;广泛的测试表明这些结果是可重复的。如果我们需要一个大的 cell,就把原 cell 复制扩大;如果我们需要更多的 cell,就复制几份 cell。
所有的实验都每个 cell 重复 11 次,用不同的随机数发生器。在图上,我们用一个横线来表示最少和最多需要的机器,然后选择 90% 这个位置作为结果,平均或者居中的结论不会代表一个系统管理员会做的最优选择。我们相信 cell 压缩提供了一个公平一致的方式去比较调度策略:好的策略只需要更少的机器来跑相同的负载。
我们的实验聚焦在调度 (打包) 某个时间点的一个负载,而不是重放一段长期的工作踪迹。这部分是因为复制一个开放和关闭的队列模型比较困难,部分是因为传统的一段时间内跑完的指标和我们环境的长期跑服务不一样,部分是因为这样比较起来比较明确,部分是因为我们相信怎么整都差不多,部分是因为我们在消费 20 万个 Borg CPU 来做测试——即使在 Google 的量级,这也不是一个小数目(译者:就你丫理由多!)
在生产环境下,我们谨慎的留下了一些顶部空间给负载的增加,比如一些“黑天鹅”时间,负载高峰,机器故障,硬件升级,以及大范围故障(供电进灰)。图 4 显示了我们在现实世界中可以把 cell 压缩到多小。上面的基线是用来表示压缩大小的。
2 Cell 的共享使用
几乎我们所有的机器都同时跑 prod 和 non-prod 的 task:在共享 Borg cell 里有 98% 的机器同时跑这 2 种 task,在所有 Borg 管理的机器里面有 83% 同时跑这 2 种 task(我们有一些专用的 Cell 跑特定任务)。
鉴于很多其他的组织把面向用户应用和批处理应用在不同的集群上运行,我们设想一下如果我们也这么干会发生什么情况。图 5 展现了在一个中等大小的 Cell 上分开跑我们 prod 和 non-prod 的工作负载将需要 20-30% 多的机器。这是因为 prod 的 job 通常会保留一些资源来应对极少发生的负载高峰,但实际上在大多情况下不会用这些资源。Borg 把这批资源回收利用了 ($5.5) 来跑很多 non-prod 的工作,所以最终我们只需要更少的机器。
大部分 Borg cell 被几千个用户共享使用。图 6 展现了为什么。对这个测试,如果一个用户消费超过了 10TiB 内存(或 100TiB),我们就把这个用户的工作负载分离到一个单独的 Cell 里面去。我们目前的策略展现了它的威力:即使我们设置了这么高的阈值(来分离),也需要 2 -16 倍多的 Cell,和 20-150% 多的机器。资源池的方案再次有效地节省了开销。
但是,或许把很多不相关的用户和 job 类型打包放到一台机器上,会造成 CPU 冲突,然后就需要更多的机器进行补偿?为了验证这一点,我们看一下在同一台机器,锁定时钟周期,每指令循环数 CPI(cycles per instruction)在不同环境的 task 下是怎么变化的。在这种情况下,CPI 是一个可比较的指标而且可以代表冲突度量,因为 2 倍的 CPI 意味着 CPU 密集型程序要跑 2 倍的时间。这些数据是从一周内 12000 个随机的 prod 的 task 中获取的,用硬件测量工具 [83] 取的,并且对采样做了权重,这样每秒 CPU 都是平等的。测试结果不是非常明显。
我们发现 CPI 在同一个时间段内和下面两个量正相关:这台机器上总的 CPU 使用量,以及 (强相关) 这个机器上同时跑的 task 数量;每往一台机器上增加 1 个 task,就会增加 0.3% 的 CPI(线性模型过滤数据);增加一台 10% 的 CPU 使用率,就会增加小于 2% 的 CPI。即使这已经是一个统计意义显著的正相关性,也只是解释了我们在 CPI 度量上看到的 5% 的变化,还有其他的因素支配着这个变化,例如应用程序固有的差别和特殊的干涉图案[24,83]。
比较我们从共享 Cell 和少数只跑几种应用的专用 Cell 获取的 CPI 采样,我们看到共享 Cell 里面的 CPI 平均值为 1.58(σ=0.35, 方差),专用 Cell 的 CPI 平均值是 1.53(σ=0.32, 方差). 也就是说,共享 Cell 的性能差 3%。
为了搞定不同 Cell 的应用会有不同的工作负载,或者会有幸存者偏差(或许对冲突更敏感的程序会被挪到专用 Cell 里面去),我们观察了 Borglet 的 CPI,在所有 Cell 的所有机器上都会被运行。我们发现专用 Cell 的 CPI 平均值是 1.20(σ=0.29, 方差),而共享 Cell 里面的 CPI 平均值为 1.43(σ=0.45, 方差),暗示了在专用 Cell 上运行程序会比在共享 Cell 上快 1.19 倍,这就超过了 CPU 使用量轻负载的这个因素,轻微的有利于专用 Cell。
这些实验确定了仓库级别的性能测试是比较微妙的,加强了 [51] 中的观察,并且得出了共享并没有显著的增加程序运行的开销。
不过,就算我们假设用了我们结果中最不好的数据,共享还是有益的:比起 CPU 的降速,在各个方案里面减少机器更重要,这会带来减少所有资源的开销,包括内存和硬盘,不仅仅是 CPU。
3 大 Cell
Google 建立了大 Cell,为了允许大的任务运行,也是为了降低资源碎片。我们通过把负载从一个 cell 分到多个小 cell 上来测试后面那个效应(降低碎片效应),随机的把 job 用 round-robin 方式分配出去。图 7 展示了用很多小 cell 会明显的需要更多机器。
4 资源请求粒度
Borg 用户请求的 CPU 单位是千分之一核,内存和硬盘单位是 byte。(1 核是一个 CPU 的超线程,在不同机器类型中的一个通用单位)。图 8 展现了这个粒度的好处:CPU 核和内存只有少数的“最佳击球点”,以及这些资源很少的相关性。这个分布和 [68] 里面的基本差不多,除了我们看到大内存的请求在 90% 这个线上。
提供一个固定尺寸的容器和虚拟机,在 IaaS(infrastructure-as-a-service)提供商里面或许是比较流行的,但不符合我们的需求。为了展现这一点,我们把 CPU 核和内存限制做成一个个尺寸,然后把 prod 的 job 按照大一点最近的尺寸去跑 (取这 2 个维度的平方值之和最近,也就是 2 维图上的直线),0.5 核的 CPU,1G 的内存为差值。图 9 显示了一般情况下我们需要 30-50% 多的资源来运行。上限来自于把大的 task 跑在一整台机器上,这些 task 即使扩大四倍也没办法在原有 Cell 上压缩跑。下限是允许这些 task 等待(pending)。(这比[37] 里面的数据要大 100%,因为我们支持超过 4 中尺寸而且允许 CPU 和内存无限扩张)。
5 资源再利用
一个 job 可以声明一个限制资源,是每个 task 能强制保证的资源上限。Borg 会先检查这个限制是不是在用户的配额内,然后检查具体的机器是否有那么多资源来调度这个 task。有的用户会买超过他们需要的配额,也有用户会的 task 实际需要更多的资源去跑,因为 Borg 会杀掉那些需要更多的内存和硬盘空间的 task,或者卡住 CPU 使用率不上去。另外,一些 task 偶尔需要使用他们的所有资源(例如,在一天的高峰期或者受到了一个拒绝服务攻击),大多时候用不上那么多资源。
比起把那些分出来但不用的资源浪费掉,我们估计了一个 task 会用多少资源然后把其他的资源回收再利用给那些可以忍受低质量资源的工作,例如批处理 job。这整个过程被叫做资源再利用(resource reclamation)。这个估值叫做 task 自留地资源(reservation),被 Borgmaster 每过几秒就计算一次,是 Borglet 抓取的细粒度资源消费用率。最初的自留地资源被设置的和资源限制一样大;在 300s 之后,也就是启动那个阶段,自留地资源会缓慢的下降到实际用量加上一个安全值。自留地资源在实际用量超过它的时候会迅速上升。
Borg 调度器 (scheduler) 使用限制资源来计算 prod task 的可用性($3.2),所以这些 task 从来不依赖于回收的资源,也不提供超售的资源;对于 non-prod 的 task,使用了目前运行 task 的自留地资源,这么新的 task 可以被调度到回收资源。
一台机器有可能因为自留地预估错度而导致运行时资源不足 —— 即使所有的 task 都在限制资源之内跑。如果这种情况发生了,我们杀掉或者限制 non-prod task,从来不对 prod task 下手。
图 10 展示了如果没有资源再利用会需要更多的机器。在一个中等大小的 Cell 上大概有 20% 的工作负载跑在回收资源上。
图 11 可以看到更多的细节,包括回收资源、实际使用资源和限制资源的比例。一个超内存限制的 task 首先会被重新调度,不管优先级有多高,所以这样就很少有 task 会超过内存限制。另一方面,CPU 使用率是可以轻易被卡住的,所以短期的超过自留地资源的高峰时没什么损害的。
图 11 暗示了资源再利用可能是没必要的保守:在自留地和实际使用中间有一大片差距。为了测试这一点,我们选择了一个生产 cell 然后调试它的预估参数到一个激进策略上,把安全区划小点,然后做了一个介于激进和基本之间的中庸策略跑,然后恢复到基本策略。
图 12 展现了结果。第二周自留地资源和实际资源的差值是最小的,比第三周要小,最大的是第一和第四周。和预期的一样,周 2 和周 3 的 OOM 率有一个轻微的提升。在复查了这个结果后,我们觉得利大于弊,于是把中庸策略的参数放到其他 cell 上部署运行。
隔离性
50% 的机器跑 9 个以上的 task;最忙的 10% 的机器大概跑 25 个 task,4500 个线程[83]。虽然在应用间共享机器会增加使用率,也需要一个比较好的机制来保证 task 之间不互相冲突。包括安全和性能都不能互相冲突。
1 安全隔离
我们使用 Linux chroot 监狱作为同一台机器不同 task 之间主要的安全隔离机制。为了允许远程 debug,我们以前会分发 ssh key 来自动给用户权限去访问跑他们 task 的机器,现在不这么干了。对大多数用户来说,现在提供的是 borgssh 命令,这个程序和 Borglet 协同,来构建一个 ssh shell,这个 shell 和 task 运行在同样的 chroot 和 cgroup 下,这样限制就更加严格了。
VM 和安全沙箱技术被使用在外部的软件上,在 Google’s AppEngine (GAE) [38]和 Google Compute Engine (GCE)环境下。我们把 KVM 进程中的每个 hosted VM 按照一个 Borg task 运行。
6.2 性能隔离
早期的 Borglet 使用了一种相对原始粗暴的资源隔离措施:事后内存、硬盘、CPU 使用率检查,然后终止使用过多内存和硬盘的 task,或者把用太多 CPU 的激进 task 通过 Linux CPU 优先级降下来。不过,很多粗暴的 task 还是很轻易的能影响同台机器上其他 task 的性能,然后很多用户就会多申请资源来让 Borg 减少调度的 task 数量,然后会导致系统资源利用率降低。资源回收可以弥补一些损失,但不是全部,因为要保证资源安全红线。在极端情况下,用户请求使用专用的机器或者 cell。
目前,所有 Borg task 都跑在 Linux cgroup-based 资源容器 [17,58,62] 里面,Borglet 操作这些容器的设置,这样就增强了控制因为操作系统内核在起作用。即使这样,偶尔还是有低级别的资源冲突 (例如内存带宽和 L3 缓存污染) 还是会发生,见[60,83]
为了搞定超负荷和超请求,Borg task 有一个应用阶级 (appclass)。最主要的区分在于延迟敏感 latency-sensitive (LS) 的应用和其他应用的区别,其他应用我们在文章里面叫 batch。LS task 是包括面向用户的应用和需要快速响应的共享基础设施。高优先级的 LS task 得到最高有待,可以为了这个把 batch task 一次饿个几秒种。
第二个区分在于可压缩资源 (例如 CPU 循环,disk I/ O 带宽) 都是速率性的可以被回收的,对于一个 task 可以降低这些资源的量而不去杀掉 task;和不可压缩资源 (例如内存、硬盘空间) 这些一般来说不杀掉 task 就没法回收的。如果一个机器用光了不可压缩资源,Borglet 马上就会杀掉 task,从低优先级开始杀,直到剩下的自留地资源够用。如果机器用完了可压缩资源,Borglet 会卡住使用率这样当短期高峰来到时不用杀掉任何 task。如果情况没有改善,Borgmaster 会从这个机器上去除一个或多个 task。
Borglet 的用户空间控制循环在未来预期的基础上给 prod task 分配内存,在内存压力基础上给 non-prod task 分配内存;从内核事件来处理 Out-of-Memory (OOM);杀掉那些想获取超过自身限制内存的 task,或者在一个超负载的机器上实际超过负载时。Linux 的积极文件缓存策略让我们的实现更负载一点,因为精确计算内存用量会麻烦很多。
为了增强性能隔离,LS task 可以独占整个物理 CPU 核,不让别的 LS task 来用他们。batch task 可以在任何核上面跑,不过他们只被分配了很少的和 LS task 共享的资源。Borglet 动态的调整贪婪 LS task 的资源限制来保证他们不会把 batch task 饿上几分钟,有选择的在需要时使用 CFS 带宽控制[75];光有共享是不行的,我们有多个优先级。
就像 Leverich [56],我们发现标准的 Linux CPU 调度 (CFS) 需要大幅调整来支持低延迟和高使用率。为了减少调度延迟,我们版本的 CFS 使用了额外的每 cgroup 历史[16],允许 LS task 驱逐 batch task,并且避免多个 LS task 跑在一个 CPU 上的调度量子效应(scheduling quantum,译者:或许指的是互相冲突?)。幸运的是,大多我们的应用使用的每个线程处理一个请求模型,这样就缓和了持久负载不均衡。我们节俭地使用 cpusets 来分配 CPU 核给有特殊延迟需求的应用。这些措施的一部分结果展现在图 13 里面。我们持续在这方面投入,增加了线程部署和 CPU 管理包括 NUMA 超线程、能源觉察(例如[81]),增加 Borglet 的控制精确度。
Task 被允许在他们的限制范围内消费资源。其中大部分 task 甚至被允许去使用更多的可压缩资源例如 CPU,充分利用没有被使用的资源。大概 5% 的 LS task 禁止这么做,主要是为了增加可预测性;小于 1% 的 batch task 也禁止。使用超量内存默认是被禁止的,因为这会增加 task 被杀的概率,不过即使这样,10% 的 LS task 打开了这个限制,79% 的 batch task 也开了因为这事 MapReduce 框架默认的。这事对资源再回收 ($5.5) 的一个补偿。Batch task 很乐意使用没有被用起来的内存,也乐意不时的释放一些可回收的内存:大多情况下这跑的很好,即使有时候 batch task 会被急需资源的 LS task 杀掉。
“Borg 使用策略是什么”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注丸趣 TV 网站,丸趣 TV 小编将为大家输出更多高质量的实用文章!