文本根据谷歌15年发表的论文整理得到,论文连接:http://research.google.com/pubs/pub43438.html
Borg是一个集群管理系统,上面运行着十万级的任务,数千个不同的应用,管理着数万台机器。其通过权限管理、资源共享、性能隔离等来达到高资源利用率。它能够支持高可用应用,并通过调度策略减少出现故障的概率,提供了任务描述语言、实时任务监控、分析工具等。
Borg主要有三大优势:
Borg的用户主要是谷歌的开发人员和管理人员,主要运行谷歌内部的应用和服务。用户以job的方式提交作业,一个job可以包含一个或多个task。每个作业运行在同一个cell中,cell是由一组机器构成的一个处理单元。
在谷歌集群中,通常包含一个大规模的cell和若干个用于测试或者特殊用途的小cell。cell的规模大约是10K个机器,其中的机器在资源大小、处理器型号、性能、容量等方面异构。
一个Borg作业Job具有name、owner、task数量等属性。Job具有约束(constraint)来强制其任务运行在具有特定属性的机器上,例如处理器架构、OS版本、IP地址等。约束可以分为硬约束和软约束,前者是需求,必须满足;后者是偏好,尽量满足。每个任务,可以映射为一个container中的一组Linux程序。Borg绝大部分工作负载不运行在虚拟机中,这主要是由于虚拟机性能开销较大,此外一些硬件不支持虚拟化。
一个任务也具有属性,例如资源需求和task index。Borg程序采用静态链接库,以减少对运行环境的依赖,软件包中主要包括二进制程序和数据文件。 用户向Borg发送RPC用以操作作业。用户可以提交作业、查询作业,也可以改变作业、任务属性。作业Job和任务task的状态图如下图所示。用户可以触发submit、kill和update事务。
任务Task在被抢占之前,会收到通知,二者都是通过Unix信号,抢占通过SIGKILL信号,程序直接退出;通知通过SIGTERM信号,可以被处理。这样做主要是为了让程序关闭前清理环境、保存状态、完成当前请求等。
一个Borg alloc是一台machine上预留资源的集合,可以用于一个或多个任务运行。Alloc被用于为未来的task预留资源,用来在停止和再次启动任务之间保持资源,或者将不同作业Job的任务task聚合在一起运行(例如一个web服务器实例和一个相关的logsaver)。
一个Alloc集合类似一个job:它是在多个机器上预留资源的一组alloc。一旦一个alloc集合被创建,一个或者多个作业Job就可以被提交在其中运行。简而言之,一个task与一个alloc对应,一个job与一个alloc集合对应。
每个作业都有一个优先级,具体形式是一个小的正整数。Borg定义非重叠优先级,包括:monitoring, production, batch, and best effort (also known as testing or free),生产型作业(prod job)包含前两种优先级。
为了避免“抢占洪流”,Borg不允许同类型作业之间的抢占,只允许生产型作业抢占非生产型作业。
资源配额Quota是一组资源量化表达式(CPU、RAM、Disk等),它与一个优先级和一个时间段对应。如果Quota不足,作业提交会被拒绝。
Borg创建了一个稳定的Borg名字服务(BNS),用于为每个任务命名。任务名字包括cell name、job name和task number这个三元组。Borg将任务的主机名和端口号写入Chubby中的一致性、高可用文件。Borg也会将作业规模和任务健康信息写入Chubby,负载均衡器LoadBalancer据此来进行路由。
每个任务会构建HTTP server来发布其健康信息和性能指标,Borg根据URL来监控任务,并重启异常任务。
borg的中心控制模块叫BorgMaster,每个节点模块叫Borglet,所有组件均使用C++编写。(基础平台使用C++书写属于惯例,能够从底层提高性能,而Java语言则比较重,不过使用Hadoop生态的还需要使用Java语言)
borgmaster包含两个进程:主进程:负责处理客户端RPC调用,管理系统中所有对象的状态机,与borglet进行通信。以及一个分离的调度器。
borgmaster在逻辑上是一个进程,但是有5个副本,每个副本都维护cell状态的一份内存副本,cell状态同时在高可用、分布式、基于Paxos的存储系统中做本地磁盘持久化存储。一个单一的被选举的master既是Paxos leader,也是状态管理者。当cell启动或者被选举master挂掉时,系统会选举Borgmaster,选举机制按照Paxos算法流程进行。选举master的过程通常会消耗10秒,在一些规模较大的cell会消耗1分钟左右。
borgmaster的状态会定时设置checkpoint,具体形式就是在Paxos store中存储周期性的镜像snapshot和增量更改日志。其作用可以存储borgmaster的状态,修复问题,离线模拟等。
此外还提供了一个模拟器Fauxmaster,其是borgmaster的一个复制品,可以用来修复bug,模拟执行。
当job被提交时,borgmaster会将其记录到paxos store中,并将task增加到等待队列中,调度器通过一步的方式扫描队列将机器分配给任务,调度过程主要包括可行性检查和打分。
可行性检查主要用于解决硬约束,找到一组满足硬约束的机器;打分则是满足软约束,在可行的机器中根据用户偏好为机器打分,用户偏好主要是系统内置的标准,如:被抢占的task的优先级和数量最小化,具有任务软件包的机器、分散任务到不同的失败域中,将高优先级和低优先级的task分配到同一个node上,使得高优先的任务可以抢占低优先级的任务等。borgmaster一开始使用E-PVN进行打分,其会将任务分散到不同的机器上,称为worst fit;而best fit会尽量使用紧凑的机器以减少资源碎片。考虑到系统中不同类型任务单额资源需求,采用混合的模型进行打分。
如果对于一个新task没有充足的资源,那么系统会杀死低优先级的任务,杀死的低优先级的任务会被放置在等待队列中。任务启动延迟平均在25秒,有80%的时间花费在包安装上。因此在调度的时候尽量把任务调度在含有包的机器上,同时因为包是不变得,所以可以共享和缓存,同时还提供了一些并行分发包的协议。
borglet是运行在每台机器上的代理,负责启动和停止task,重启任务,管理本地资源,向master和监控模块汇报自己的状态。master会周期性的向borglet拉取其当前的状态,这样做能够控制通信速度避免“恢复风暴”。
为了性能扩展,master副本会运行一个无状态的link shard去处理与部分borglet的通信,但重新选举时会重新分区,master副本会聚合和压缩信息,向被选举的master报告状态机的不同部分,减少更新负担。如果borglet多轮都没有进行响应会被标记为down。运行在上面的任务会被重新调度至其他机器,如果通信恢复,master会通知borglet杀死已经重调度的任务保证一致性。
虽然现在还不确定borg的中心式框架的可扩展性极限在哪里,至少现在还没有遇到极限,一个master可以管理数千台机器,每分钟处理上万个任务,一个master配置10-14核CPU和50G内存。
为了提升可扩展性,我们将调度器分割为独立进程,这样它可以与Borgmaster并行进行操作。调度器具备多个副本,每个调度器在cell状态的副本上进行操作。它重复以下操作:从被选举master中检索状态变更;更新本地状态副本;进行调度、分配任务;将分配通知被选举master。Master会检查调度器的调度操作,如果发生调度冲突则再下一轮重新调度,否则接受并应用该调度结果。这套机制与Omega一文中的乐观并发控制高度相似。此外,Borg最近支持为不同负载类型使用不同调度器。
为了提高系统可扩展性,Borg调度器还作了三个方面优化:(1)得分缓存:可以将可行性检查和打分结果缓存下来;(2)等价类:同一job中的task通常具有类似的约束,因此可以将多个任务视为一个等价类;(3)随机化:大规模计算所有机器的得分代价太大,通过随机遍历机器找到足够多的满足可行性的机器,然后对这些机器进行打分。
可用性对于分布式系统非常关键,borg通过一系列的优化能够使其可用性达到99.99%。
实验部分主要运行谷歌内部的任务,首先通过实验证明混合部署比独立部署具有更高的利用率,结果如上图所示。然后通过实验证明了几种提高集群资源利用率得方法,包括cell sharing(处理单元共享,评价指标CPI),large cell(大处理单元), fine-grained resource requests(细粒度资源请求)和resource reclamation(资源矫正后者理解为资源超售)。
对于资源超售部分说明:
由于集群资源共享,所以每个机器不可避免会运行不同的任务,这就需要有一套较好的机制来确保这些任务之间的影响最小。
Borg按照两种方法来控制overload和overcommitment,overload通过将任务分为Latency-sensitive(LS)和batch两种来控制资源;overcommitment则通过任务对资源的占用划分为compressible(例如cpu、I/O带宽)和non-compressible(例如内存、磁盘空间)。
如果机器上non-compressible的资源不够用了,那么Borglet会立刻按照优先级杀掉本机上优先级低的任务释放出资源;如compressible的资源不够用,那么Borglet会先尝试控制batch任务对cpu的使用来度过高峰,如果还不行,就会由borgmaster拿掉机器上的一个或更多的低优先级任务。
Borglet里面还有一个用户态的程序来控制分配给prod和non-prod任务的内存,如内存超过了task的限制,或本机的内存不够用了,内核中处理OOM事件的部分将按照优先级来kill task。
在CPU方面,在资源的分配上,对于LS tasks允许占用整个cpu核,而batch tasks则可以在任何核上运行,但batch tasks会在较低优先级上,Borg修改了内核的CPU调度器,允许根据每个container的load状况来动态决定是否要kill batch tasks,同时避免多个LS tasks在一个cpu上争抢,目前Borg仍然在尝试的是在cpu调度时更好的考虑线程亲和、NUMA亲和之类的。
参考Google大规模集群管理系统Borg解读