Borg的一个主要目的就是有效的利用Google的机器舰队,这但是一大笔财务投资:让效率提高几个百分点就能省下几百万美圆。这一节讨论了和计算了一些Borg使用的技术和策略。shell
咱们的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。app
全部的实验都每一个cell重复11次,用不一样的随机数发生器。在图上,咱们用一个横线来表示最少和最多须要的机器,而后选择90%这个位置做为结果,平均或者居中的结论不会表明一个系统管理员会作的最优选择。咱们相信cell压缩提供了一个公平一致的方式去比较调度策略:好的策略只须要更少的机器来跑相同的负载。框架
咱们的实验聚焦在调度(打包)某个时间点的一个负载,而不是重放一段长期的工做踪影。这部分是由于复制一个开放和关闭的队列模型比较困难,部分是由于传统的一段时间内跑完的指标和咱们环境的长期跑服务不同,部分是由于这样比较起来比较明确,部分是由于咱们相信怎么整都差很少,部分是由于咱们在消费20万个Borg CPU来作测试——即便在Google的量级,这也不是一个小数目(译者:就你丫理由多!)ssh
在生产环境下,咱们谨慎的留下了一些顶部空间给负载的增长,好比一些“黑天鹅”时间,负载高峰,机器故障,硬件升级,以及大范围故障(供电进灰)。图4显示了咱们在现实世界中能够把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。
Google创建了大Cell,为了容许大的任务运行,也是为了下降资源碎片。咱们经过把负载从一个cell分到多个小cell上来测试后面那个效应(下降碎片效应),随机的把job用round-robin方式分配出去。图7展现了用不少小cell会明显的须要更多机器。
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和内存无限扩张)。
一个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之间不互相冲突。包括安全和性能都不能互相冲突。
咱们使用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运行。
早期的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杀掉。