面向容器的资源调度技术对比
摘要:本文以资源分配理念,拍卖、预算、抢占出发,引出 Borg、Omega、Mesos、Kubernetes 架构、数据、API 的特点比较。然后梳理资源共享各种不同共享形式的内容,接着对比任务类型,最后回到资源利用率和基于数据预测角度,看相关系统是如何运用和实现各自场景目标。最后给出阿里巴巴电商在线服务资源调度器 Zeus 关键技术内容。
进入这个领域的门槛不在具体某个技术,而业务场景和技术选型的映射匹配,特别是周边系统的完善程度,决定了如何选择方案、如何制定落地计划。本文不是为了全面分析某个调度器,也不是全面对比某个关键点在不同调度器之间特色,而是基于笔者的理解,阐述在一个新场景下,如何设计或者完善一个资源调度器,从已有调度器系统吸取架构或模块经验,最低成本实现贴合自身业务场景的资源调度器。例如吸取调度器二层架构模式、数据集中管理方式、统一 RestFull API、资源分时共享策略、在离线任务类型抽象等。
1 从资源分配理念来看已有调度器
在资源调度器中,资源分配理念:拍卖、预算或抢占,往往是混合运用。资源分配理念,折射出了资源调度器所在的生态系统或者说周边配合系统的成熟度、运行习惯。例如,Google 从最早的广告拍卖机制起,拍卖的理念在 Google 内部就形成了一种经验,那么资源竞拍被分配出来的结果,大家很容易达成一致。而国内企业,往往是预算驱动,更趋向预算、采购,谁预算谁使用。这种环境下,资源被谁使用基本可以预见,成本也是比较容易找到归属者。在拍卖机制下资源抢占,初始分配是不大会发生,只有在运行时发生资源不够用的时候出现,低优先级的任务被 Kill。在预算机制下,资源分配初期、运行时过程中,都会发生抢占。拍卖的另外一种好处是便于资源流动起来,不仅是资源利用率提升,更是资源投入产出比的最大化。而预算往往是一次性的,重点业务资源优先保障,使得适应性、灵活性、激励业务效率提升变得不如拍卖。
不同策略落地在架构、数据、API 层面有着非常多的共同之处。从中不难发现 Borg 是始祖,后来的 Mesos、Omega、Kubernetes、Zeus 等都延续着 Borg 的某些重要特征,而又随技术发展,引入新的特征。针对每个系统的具体分析,可以参照各系统发表过的论文及官方文档[1,2,3,4,5,6,7]。
1.1 架构层面
Borg
调度器架构图如图 1 所示[2],是 Google 建造的一个主控制核心,管理公司所有的数据库。两级优先级:服务性的高优先级和批处理的低优先级。两阶段调度:找到可行的节点,然后为最终放置对这些节点评分。
图 1 Borg 架构图
Borglet 向 Master 汇报状态,从而 master 确认 borglet 是否存活,以及是否需要执行 Borglet 上的任务迁移等操作。任务、资源的状态数据更新是周期性的,而不是变化通知机制。
Job 使用 BCL 来描述,通过 RPC 命令 tool 提交到 Borg master。Borg 大量的调度任务属于 Jobs,但是集群 70%左右的 CPU 是给 service 的。
Borg 一层框架,在框架上跑 Schedule。框架是 Borglet 和 BorgMaster 之间进行状态通信,确保资源存活性、任务运行时数据收集,同时 PAXOS 协议,确保多 master 数据一致性,支持并发和容灾。而 Schedule 与 BorgMaster 进行数据读写,实现资源的分配和回收管理等。
Mesos
Twitter 研发的超级网络系统,Mesos 的出现比 YARN 早,引入两级调度的理念。两级调度通过一个名为资源邀约的新 API 发起,邀约是有时间限制的,激励应用程序去实现快速地调度。Mesos[3]里面并没有拍卖的影子,更注重公平性,允许短任务预留一些资源。时间期限就是资源的共享的生命周期。在 Mesos 中,资源邀约是悲观的或独占的。如果资源已经提供给一个应用程序,同样的资源将不能提供给另一个应用程序,直到邀约超时。
Borg 和 Mesos 并不只是能让他们的服务器群智能化处理他们的数据,他们还让管理集群就像操作一台机器一样处理所有的数据[7]。
Omega
重点在介绍基于状态的资源管理组件,Omega[4]的资源管理器基本上,只是一个记录每个节点状态的关系数据库,使用不同类型的乐观并发控制解决冲突。这样的好处是大大增加了调度器的性能(完全并行)和更好的利用率。
Omega 采取多版本控制的、乐观锁机制在遇到偶尔的资源冲突时候。所有资源状态存储在基于 PAXOS 协议实现的事物系统中,外部调度器访问并执行资源调度。
Kubernetes
作为 Docker 生态圈中重要一员,由 Google 开源,整个设计重点之一在于方便分布式复杂应用的部署和管理[5,6]。Kubernetes 吸收了 Borg 使用过程中大量的实践经验,当然整个系统因为涵盖的功能较多,延续 Borg 完备、复杂性,相对 Mesos 等稍微简单些。Kubernetes 面向云端,需要考虑的功能点非常多。例如网络、负载均衡、资源管理、高可用、镜像更新、存储、安全、监控等。Kubernetes 架构如图 2 所示。
图 2 Kubernetes 架构图
总结:主动、定时汇报的框架,还是变更通知的框架比较适合呢?状态基于 PAXOS 协议分布式事务一致性,还是集中数据库存储?基于实践的成本、简单性、阶段目标出发,变更通知和数据库可以精简系统、快速搭建原型。如果要应对百万级服务器,那么 PAXOS 协议、定时汇报应该就是标配的技术方案了。通知模式,消息重发(发的频率、次数)、消息处理(脏数据、临界数据)、数据补偿等需要仔细设计,避免时不时的消息数据错误导致资源使用不一致,引发后续解救。PAXOS 协议脑裂是一个潜在的风险,但是,相对通知模式还是显得优雅和透明些。
两级调度:第一级选择机器(也就是业务编排),第二级分配容器资源。或者第一级选资源,第二级业务编排组织。这个过程,局部最优可以加速资源调度性能,全局最优可以获取最佳的资源位。具体场景具体选择,并且都可以作为参数传入调度器。
两种或多种优先级:高优先级、低优先级,分别对应在线服务、监控服务、运维服务,离线短周期 Jobs、批量 Jobs 等。业务优先级的定义和变更,需要业务层面全局的评估和系统自动化更新,并及时反馈到调度器中。业务方都趋向把自己的业务定位高优先级。确定不可抢占业务。
并发支持的程度和粒度,面向链路也就是队列,还是面向资源状态。每次申请资源全局最优还是局部最优,一旦发生冲突,乐观锁还是悲观锁。实践经验,先解决业务需求,求得生存,然后优化性能。
在整个架构之外,模拟器也是非常重要的子系统。尤其是资源调度器这种基础的服务系统,资源一旦分配错误或者不可用,造成的影响非常大。整个结构友好的支持模拟数据进行算法验证必不可少。总是假设,容器技术、生态的其他产品都是可信赖、高可用、跨语言 API 服务的。
1.2 数据层面
Borg
在 Google 已经运行了 10 多年,是一个效率极高的系统。典型的 Borgmaster 使用 10 至 14 个内核和 50GB 内存,数据主要集中在内存。1 分钟启停 1 万个 task 进程。99%的 Web UI 响应时间小于 1s,95%的 polling borglet 时间小于 10s。针对成千上万节点,每分钟调度的速率为 10K 任务。典型调度时间是 25 秒左右(这依赖于具体节点的本地化。下载二进制占这个时长的 80%,Torrent 和树协议用于分发二进制文件)。单个 cell 内部 98%机器都是混跑(prod/non-prod, long-running service/batch jobs),整个 Borg 系统中 83%的机器是混跑。意味着 Google 资源共享不是简单的固定配额共享,又或者整机交付的共享,而是实时动态的共享。
在混部 CPI 方面,增加作业会导致其他作业进程 CPI 增加 0.3%(CPI 越大表示程序执行越慢),机器 CPU 使用率每增加 10%会导致作业进程 CPI 增加 2%。混跑集群平均 CPI 1.58,专用集群 1.53。另外 Borglet 的 CPI:混跑 1.43,专用 1.20。结论:CPI 差别不大,因此混跑并不会显著的降低程序运行时间!资源利用率主要的度量指标是单元压缩。也就是一个业务单元使用的资源最小化程度。一个典型的 cell 中,prod 作业调度占 70% CPU,55%Memory,实际使用占 60% CPU,85% Memory。通过 Borglet 的周期性、实时计算,调整资源实例的配额,从而进行资源压缩。
配置或者 Jobs 调度参数等都以 JSON 或者 YAML 格式实现。
Google 的效率,从 Google 一个 PE 可以运维上万台服务器,可见相当先进了。
成本计费方面:将 Job 的提交、配置、具体每个 task 的资源使用情况都保存到一个数据库中,并提交 SQL 查询,供计费、debug、错误分析、容量规划。
Mesos
更关注资源公平性,简化了 Borg 的复杂性,做得相当薄,只有 10K 行代码。
Omega
典型的集群利用率约为 60%。秒级的调度时间是典型的。
Kubernetes
Google 开源的 Golang 语言实现的、支持 Docker 容器的新一代资源调度器。和 Borg Omega 一样,都有一个共享的持久化状态存储模块,用于实现资源状态一致性。Borg 的 Job Conf 里有 230 个参数,用户 tune 代价大、易出错,Kubernetes 做了参数的自动化适应。
总结:数据也就是资源状态以及调度分布数据,持久化 DB 还是 Paxos 协议实现的分布式事务存储,没有最好,只有更好。不过,提供 API 查询,特别是页面可视化操作,都是必须的。有时候对资源分配的结果,也是需要可解释的,这依赖数据可视化、中间过程透明化。
流程或者分配或者运行时或者异常故障等数据的沉淀,用于故障分析、完善周边系统、动态修正实例配额、容量水位、容量准入。数据沉淀并分析是非常有价值的。
成本计算基于调度器历史过程申请资源的使用规模和时间,还是基于业务预算的资源,还是最后落地的流程记录数据,不论哪种方式,对资源的粒度和时间片的统一界定非常重要。
所有对数据的操作在资源调度器层,尽量限制在原子层面,流程或者业务数据一致性交给上层或者业务发起端控制。这样,资源调度器层基本无状态、原子更新,分布式一致性就比较简单、集中。业务需求,交给业务处理。如果业务层校验或者其他要求,资源不满足需求,要么业务层自我修复,要么业务层要向链路下游层层回滚,最终确保资源调度器资源申请和使用最终一致性。否则,资源数据不一致引发资源超卖或者资源提前“用完”,而实际有资源的尴尬。
1.3 API 层面
Borg
缓存的机器分数、每种任务类型计算一次的可行性,在做调度决策时,不要试图全局最优。复杂的规范语言。整个 master 是一个 API server,其他的调度、admission 管理都是作为服务,以 client 访问 API server,对外提供丰富的生态工具,例如脚本、web 管理页面、控制台命令等。通过 Http 协议实现的序列 API,执行容器到资源分配管理的几乎全部操作。支持以标签形式动态调整应用的属性,从而影响 Jobs 调度策略。
Mesos
Mesos API[3]包括 SchedulerHttp、Executor Http、internal C++ API。Mesos 已经开始引入更多 Kubernetes 的概念来支持 Kubernetes API [3]。仔细的比较 Mesos、Kubernetes 两者的生态、开源社区发展,两者之间的竞争是明显的。虚拟机友好化、容器类(例如 Docker)友好化的 API 或者二次开发,成为业界选择的焦点。Mesos 目前对计算集群支持的比较友好,而 Kubernetes 对虚拟机,尤其是云端支持的更友好。
Omega
Omega 基于 Borg 发展起来的 Google 新一代系统,Omega 论文并没有给出详细 API 说明。Omega 重点在对比过去的架构和新架构的优势,API 猜测基本延续了 Borg 的相关功能。当对比讨论 Omega 的时候,Mesos 已经开源,许多概念已经在 Mesos 中实现了。当讨论 Kubernetes 的时候,自然想到 Mesos 的冲击力,并随着 Docker 容器技术的兴起、云计算的发展,人们开始忘记 Omega,似乎只有 Mesos 和 Kubernetes,以及共同的祖先 Borg。
Kubernetes
Kubernetes[5]从新开始,为不同调度器组件提供一套干净的 API。Kubernetes 做了参数的自动化适应。采用专门的 RESTFULL API 提供服务。Kubernetes 是用 Golang 语言写的,它轻量、模块化、可移植还有扩展性。
总结:参数 JSON 格式化、请求跨语言支持 RESTFULLAPI,或者自定义一种描述语言。从面向机器到面向应用,调度器承担的责任由薄到厚。不过,多语言、跨平台支持能力,特别是参数和响应格式的统一是基本要求。
API 完整定义了调度器的功能边界、服务规范程度、迭代升级效率、以及和周边生态系统的交互形式等。从已知的序列资源调度器来看,Http 协议、JSON 格式参数和响应,没有理由不遵守。
所有 API 的交互,建议异常信息贯穿整个链路,并且添加各个链路的标识,这样在一个生态型的资源调度体系内,进行故障排查或者调试业务过程,具有非常大的便利性。
2 从资源共享来看已有调度器
资源共享的过程离不开两个维度:资源粒度、时间片。资源的效率=Σ(在线资源粒度*时间片*利用率) -Σ(资源离线粒度*时间片)。资源效率包括两部分,在线部分和离线部分,离线部分主要是机器故障到恢复的过程,优化这部分资源效率,提升服务器在线率。软硬件故障通用措施有:故障预警、故障检测、故障自动修复、故障自动化处理流程等。效率简单的按照在线减去离线,只是为了描述:减少离线的浪费,有利于总体资源效率的提升。实际计算出来的数值不一定和真实现状相一致的含义。下面章节提到的资源共享,主要是在线资源部分。
不论哪种资源共享形式都没有好坏之分,只有合适与不合适服务的业务场景,并且最终有无实现资源的充分利用。往往是多种方式存在于一个大的系统里面。可能针对这个场景是固定配额,另外一个场景是动态配额,对于 A 业务是集群独占,对于 B 业务是混合部署。
语言的差异也会影响共享方式。例如 Java 语言,对内存资源就没法做到不重启而动态调配内存。C++语言可以根据进程历史内存消耗,动态地释放内存给邻居进程。而 CPU、NETIO、DISKIO 等,可以动态的分配资源占比。例如 Borg,CPU、NETIO、DISKIO 看作可压缩资源,而 Memory size、Disk Size 不可压缩资源。如果不可压缩资源(如 Mem,disk 空间)紧张,Borglet 立即开始杀进程,从低优先级开始直到资源不紧张。如果可压缩资源(CPU,IO 带宽)紧张,Borglet 开始约束进程的资源使用,优先保障 latency-sensitive 的进程(如 long-running service)。如果仍然紧张,Borgmaster 开始迁移走一些 task 进程。可以看出,Borglet 不是固定配额给 service 和 jobs,而是动态统一控制共享。运行时 CPU 等资源调配在 Borglet 端可以直接执行的,而不是外界主动发起、触发 BorgletAPI 执行相应操作。
2.1 固定配额:悲观
固定配额,是指实例启动前和运行期间,实例占用的资源规格保持不变。或者物理机或者集群在混部过程,对某一类型的任务分配固定的资源占比。例如,单实例 2 个 CPU 逻辑核、4G Memory 空间、20G Disk 空间,磁盘 IOPS、网络 IOPS 最大 100MB/s 等。例如物理资源层面,整个资源 70%给在线服务,30%给离线服务。在线部分分配多个实例或者离线部分启动多少 JOB,资源总和不超过各自的比例上限。通常固定配额主要使用场景是在线 Service。在线 Service 类型任务往往是 long time running, 服务响应时间优先。在线服务即使需要资源压缩,往往也是实例数量层面,也就是容量水位层面进行控制,几乎不会执行动态的实例规格调整。不过也有例外,如果通过一段时间的数据收集处理,发现实例规格缩小或者放大,资源利用率更高或者响应时间更好,那么,会执行新的规格升级。
2.2 动态配额:乐观
动态配额,是指实例运行期间,CPU 或 Memory 或 NETIO 等根据实时运行需求,进行动态的调配,只要所在物理机资源够用。动态配额模型,一旦支持动态的增加,也就意味着支持动态的减少,也就是一旦资源不够用的时候,高优先级任务继续运行,低优先级任务逼迫释放资源,甚至 Kill 进程或者服务,进行硬降级。或者停止服务的某些子功能,释放部分资源,进行软降级。不难发现,动态配额往往是混部场景,并且被 Kill 的也是离线的 JOBs。这带来另外一个问题,离线 JOBs 管理模块,能够及时知晓 JOBs 的全局状态,并及时重新在新的位置启动 Job,确保任务的总体 Job 数量和计算能力。
前面提到,可压缩资源可以做到平滑伸缩,不可压缩资源往往需要实例重启。对于 C、C++ 伸缩更方便,伸缩时间片可以更小,而对于 Java,成本相对较高,需要重新启动 JVM,伸缩时间片更大。
更大粒度的动态化,例如对在线 service 所在的实例集群,进行批量下线,批量释放整机资源交给离线或者其他服务系统。时间片到了,离线任务被迁走,在线服务实例启动。这种方式隔离比较彻底,在线和离线之间几乎没有影响。特别是在线、离线底层基础环境不统一的时候,可以做到升级解耦。而对于基础环境统一的系统,也可以方便在线、离线各自对物理机层面的参数调整、充分挖掘物理机资源效率。
在一个大的资源体系内,可能 A 集群是更大粒度的动态化,B 集群是小粒度的动态化。依赖周边工具系统非常成熟,才能做到快速在线、离线环境隔离、环境上下文切换。并且调度系统能够瞬时感知并支持集群容量变化。很好的实施大粒度变化,更依赖周边系统工具。
2.3 分时租约共享
时间片的选择,不是孤立的,往往和一定的资源共享粒度紧密相关。分时租约,在 Mesos 里面就是邀约方式,时间片到了,资源就强制释放。租约的优势在于,时间片的长度已知。对于离线任务,吞吐量优先的场景,那么可以充分利用 Jobs 的运行时间,合理调配,充分进行资源的并发调度,提升吞吐量,包括错开时间片内的峰值消耗。类似于流水线作业,让 CPU、IO、DISK 合理发挥作用。
2.4 分时随机共享
分时随机共享,可以看作分时租约的一般化场景。随机对资源粒度、时间片、上下文切换的能力要求更高。从 Borg 论文看,分时随机共享,更多的是离线任务共享在线服务所在资源,资源一旦不够用的时候,离线任务将被 Kill。而在线任务压力较低时候,IO 等资源可以向离线任务倾斜而不影响在线服务的前提下。C++这种语言实现的任务特别适合,对 JVM 这种,只能在 CPU 层面实现随机调整。
不论时间片的大小、时机的选择,都需要一个强大的容器技术来实现资源的快速隔离、敏感的资源监控系统,进行资源消耗的追踪、预测、调配。更上一层任务管理系统,能够感知任务的存活和进度,并进行任务层面的调度。
2.5 资源预留
资源预留,可以减少任务被 Kill 掉、被迁移的次数。在资源紧张的情况下,可以快速从预留的资源池,快速的影响资源请求。从弹性效率看,对于批量的、针对在线服务的容量水位控制,加速一次批量的成功率,特别是大资源坑位的快速交付,资源预留也是非常好的措施。从容灾的角度,不同机房考虑其他机房整体不用的时候,承担其他机房迁移过来的流量,相应的资源预留也有必要的。
资源预留的客观性需求,必然牺牲一部分资源的利用率。恰当的预留规模就显得非常必要了。至于预留多少,没有绝对的指标。不同于银行存款准备金率,该数值直接影响资金的流动。资源预留更多的是效率、应急响应所需。
3 从任务类型来看已有调度器
资源调度器服务的任务类型,主要分为 Jobs、Services。Jobs 的特点:短周期,也有长的运行 1 天甚至 1 个礼拜的,大部分运行周期是分钟级别;批量提交、运行;吞吐量优先;CPU、IO 密集型;优先级相对低些;失败后可以重新分配;函数式的过程,也就是多次运行结果,只要输入不变,结果也一致的。Service 的特点:长周期,也有运行 1 天甚至 1 个礼拜的;活动营销型服务;大部分运行周期是季度或者年的,提交后就一直运行;服务响应时间敏感;CPU、IO 密集型都有;优先级特别高。有些基础类型或者管控系统,有时候也作为 service 任务看待,这些系统不允许被抢占。例如,基础存储系统、监控运维系统、权限风控系统等,这些没有直接服务外面客户,但对业务稳定性、可用性至关重要。做到任务资源不抢占,也就是固定配额模式,带来好处:业务之间彼此的影响相对比较小。不好地方:资源分配不合理或者突发需求更多资源的时候,资源浪费或者资源吃紧。在一个大的资源调度管理生态系统中(周边依赖非常多的工具、平台,而不是仅仅一个调度器就搞定),抢占必然发生的,抢占的对象、范围、频率、时机,在不同的场景下,以不同策略应对。
3.1 分配时抢占
分配时抢占,例如在不同优先级别任务共同部署在一个集群的时候,当出现更高优先级任务实例需要资源时候,空闲资源又不足以应付,此时,低优先级任务实例将被 Kill,释放资源。或者直接叠加到低优先级任务所在资源位置上。分配时抢占往往是约定的规则下执行的。为了最小化应用之间的影响,抢占尽量不集中在一个点或者一个应用或者一个业务层面,风险分散式折中。任务能被 Kill,默认要求被 kill 应用是无状态的,这样资源够用的时候,可以自动恢复。另外抢占之后,即使从资源配额角度看,实例资源的诉求都满足,从业务稳定性、综合负载均衡看,热点尽量避开。在高负荷运作的集群,添加资源或者释放资源都需要综合评估。
3.2 运行时抢占
运行时抢占,多半牺牲离线 JOBs,如果离线 JOBs 没有,那么偶尔会牺牲在线低优先级 Service。运行时抢占,对容器技术要求比较高,需要快速资源释放、重新分配。在计算密集型场景下,CPU 动态调配确实带来非常好的效果。如果整个宿主机资源已经吃紧,再怎么调配 CPU,也不能缓解压力。在线 Service 内存、磁盘空间大小往往不是瓶颈,磁盘 IO、网络带宽的使用,可以进行软降级。
对于被系统中断等使用的 CPU 核,尽量不要使用这些计算资源服务应用。毕竟和系统中断抢资源,非常不明智的。
基于 Linuxcgroup 实现的 CPU 共享:CPU 子系统和 CPU set 两种方式,针对运行时的抢占效果的好坏,需要通过真实场景观察确定。因为业务特征对效果有一定影响。业务对时间的敏感性,磁盘 IO、网络 IO 的队列技术,就需要慎重使用。
4 资源利用率和预测运用
资源利用率在第 2 部分已经提到,与资源粒度、时间片、利用率、服务器在线率等都有关联。这些抽象层面背后,还有那些方面需要仔细实施,以确保最终的效率、利用率的提升。下面列举部分信息如下。
4.1 负载预测
负载预测,预测的实时性、准确性,应用实例规格的优化、运行时动态资源的分配、全局热点把握,都是至关重要的前置技术。
负载数据主要包括 CPU 利用率、Memory 消耗、Disk 消耗,磁盘 IO、网络 IO,甚至 DB IO 等。从这些历史数据中,多维度对应用、应用实例层面分别给出面向不同时间片大小的预测值,其实是非常具有挑战的事情。数据规模、采集的并发实时性,噪声和突发流量甚至限流等,都对模型的响应时间、模型的准确率提出了很高的要求。因为错误的预测可能导致意想不到的调度影响。
负载预测和业务 QPS、RT 关联起来,甚至和能源消耗、成本关联起来,除了趋势评估,还可以帮助决策。由此对数据的协同分析,也需要专业的团队进行跟进。[12,13,14,15,16,17]
4.2 迁移最少
在资源调度系统甚至任何系统中,都会存在例外,存在系统规则或者模型无法应对或者之前没有预估到的案例。迁移最少,大型资源池调度过程中,也是需要考量并优化的点。迁移成本,包括迁移的次数、迁移的规模、迁移的影响。
物理机故障不可避免,按照万分之三的概率计算,一万台服务器,每天大约 3 台服务器触发硬件故障,这些硬件故障上面的实例要么直接不工作,要么从新创建。无状态的,直接扩容,有状态的涉及到数据搬迁。
集群碎片整理或者负载整理,都需要对实例进行上线、下线操作。迁移的过程,其实就是服务资源“暂停”服务的过程。迁移次数、规模不得不考虑。
有时候就是纯粹的资源替换,因为网络或者机型或者业务需要,做到迁移最少,在资源预算或者业务规划时候必须考量。看起来不是资源调度器的责任,但是,初期需要资源调度器的建议,从而降低二次梳理成本。
对于依赖性的 JOBs,在业务开始时候,就应该考虑依赖关系。典型的数据搬迁、服务调用,做到同一机架或者交换机都带来性能提升。一种迁移最少的方案参考论文[10]。
4.3 等待最短
在微观层面,资源调度器资源调度,特别是大规模 Jobs 调度,排队以及排队开销客观存在。排队的长度和公平性,有时候很矛盾的。降低排队时间,一方面提升业务体验,另外一方面资源分配效率更高,资源在线工作时间片更多,资源利用率也就更好。
各种应对等待的队列算法,例如轮询、带权值、优先级,都有各自的优缺点。具体场景需要具体选择[8,9]。
4.4 碎片最少
碎片最少是默认的,实际选择执行的路径有所不同。空闲优先,也就是铺开优先。另外一种是饱和优先,也就是紧凑优先。在相同资源、相同碎片的时候,是优先向空闲结点部署,还是将已有结点打饱和,没有绝对的标准。方便大规格资源的申请,那么打饱和比较妥当,这样相同碎片量的情况下,大块资源比较多。
在计算碎片的时候,需要综合评估 CPU、Memory、Disk 等维度,通常 CPU 是核心竞争资源,优先评估 CPU 的碎片。确保 CPU 关键资源的充分利用,CPU 资源在容器或者实例层面,很容易动态调整而不需要重新实例化等。一些碎片最少的算法参考论文[11]。
如果实际分配过程中,确实存在碎片无法分配出一个资源位,那么可以将余下的 CPU 核绑定到已知实例上。虽然 CPU 资源利用起来了,如果上层流量均衡调度,那么,这种相对其他实例多出的 CPU 资源,可以提升响应时间,但是并没有提升 QPS,只对稳定性有帮助。
4.5 资损最少
VM 代价计算模型当中,除了资源粒度、时间片等因素外,还需要考虑资损,尤其是电商交易类在线服务。服务器状态异常或者故障,有时候会有造成用户或者商家或者企业的财务损失。尽管业务架构层面会极大程度规避这种情况的出现,实际过程中,如果把资损最少融入常规调度策略中,那么,一旦发生局部集群的大面积故障,资损理论上就降到最低。在已知的资源调度器中,代价更多的集中在资源本身,也就是 IAAS 层考量,而把业务层的需求,例如,资损最少交给 PAAS 或者 SAAS 层解决。从最初的小型机、商用数据库、专有集群等,到分布式普通机器,自研发系统,不同阶段的技术形态和投入是不一样的。整个链路层面,层层把控资损,其实最后落到资源调度器层面的影响相对较少。
另外一个角度就是业务性价比,总是期望将业务收益最大、故障影响最敏感的系统,独立部署,资源优先保障。例如广告系统。
4.6 快速恢复
在有限资源的系统里面,或者高负载运作系统里面,局部故障的影响会被放大。在大规模的资源系统里面,每个应用的实例规模比较大,重启或者上下线实例,几乎没有丝毫影响。失败的流量占比几乎可以忽略,失败的请求重新分配到其他结点,对其他结点的压力增长也是微小的。但是,几乎每个结点压力都达到阈值 90%左右的话,那么,即使是很少量的结点故障,影响也会放大。例如,秒杀或者抢购商品,实例的稳定性要求非常高。很难做到机器 100%无故障,除了业务容量冗余之外,故障快速恢复可以减轻故障影响。
和资损类似,故障快速恢复落到资源调度器层面的责任或者压力,其实非常微弱,甚至可以忽略,除非是特殊的业务。针对故障物理机承载的实例重启速度的分布,进行有效的控制,可以从微观层面,提升故障的快速恢复能力。
5 阿里电商调度 Zeus 实践
在第一部分的架构、数据、API 分析总结里面,已经把阿里的一些实践经验概要描述了一下。本部分从整体上对 Zeus 进行概要总结。
5.1 上下游架构
阿里电商业务的复杂程度,很难用一个图或一句话描述清楚。从资源调度的层面看,阿里的在线服务资源调度系统 Zeus 依赖或者配合的系统,多达十几个。每一个被依赖的系统,除了服务资源调度器之外,还服务其他场景。下面以 Zeus 实际运作过程中关联或者依赖的视角,给出整体抽象架构示意图,如图 3 所示。
图 3 阿里在线资源调度架构
Zeus 向下,依托阿里自有 IAAS 服务,例如核心的容器技术,运维监控的底层通道系统。对上,衔接运维发布系统、监控视图、环境巡检、打标系统等等。Zeus 提供资源调度过程和结果的可视化数据视图。对接成本容量管控,在资源申请、回收、成本核算等整个资源生命周期,提供相关数据服务。
通过模拟演练,配合流量压测、追踪调度系统,提前发现不合理部署并自动调配。做到大促高峰流量场景下,业务的高可用,低成本开销。
5.2 调度策略
基于预算的统筹安排,这意味着资源存在某种程度的“边界”:就是“预算”。超出预算就变得很被动。为了提升资源利用率,负载均衡,需要跨资源边界的共享,以共赢合作方式来推动。而 Google Borg 的竞拍模式,从一开始资源是面向所有组织业务、相对公平的。两种模式选择都不是凭空的,都是伴随企业自身技术发展、贴合各自实际业务特征产生的。没有优劣,只有合适与否。
Zesu 支持在线、离线混合部署。一种,在离线任务固定配额,在单机或者集群层面固定配额,此时,在离线之间的资源争抢是可以预知的,或者说资源的边界不打破,理论上就不存在资源的干扰。这种模式,有实践过。另外一种,在线离线任务的运行时资源抢占,当在线任务资源紧张,单节点离线任务就需要释放 CPU 或者磁盘 IO 或者网络带宽资源。
抢占发生的时刻,除了初始分配、也包括运行时时刻。例如,在线和离线之间抢占,甚至包括在线任务之间的资源抢占。
另外一种抢占,或者说资源倾斜,或者说业务管理需求吧。在线任务又细分中间件基础服务、运维监控基础服务、安全风险控制等业务模块,这些重要的业务资源优先保障,不被抢占。
对待碎片,总体上碎片最少。候选资源结点排序上,铺开优先和紧凑优先都有。看具体资源池和对应业务的需求而定。用于特殊场景下,甚至存在运行时动态确定资源的策略,例如秒级别响应资源服务需求。
故障预警、故障检测、环境巡检、打标、提升资源在线率、流程数据一致性等,也有相应的策略。例如:基于 Golang 实现的队列,支持配置的批量更新、采集等。基于 Golang 协程和 Map,实现多级并发的机器选择和计算得分排序等。
5.3 利用率和预测
资源利用率相对阿里过去有不少提升,每年节约成本亿为单位。相对业界,特定的资源池利用率达到甚至超过业界水平,总体打平的利用率,与业界还有一些差距。这些差距和业务场景、内部依赖配合的系统工具的成熟度、发展计划都有关联。
预测目标是某种程度把整个系统的流转过程,数据化、模型化、自动化。预测的能力某种程度决定了资源调度系统最终能达到的理想状态。在阿里内部,针对在线或者离线任务的负载预测、容量水位预测、全链路模型等,都有相关的团队在负责,并经历了几届双 11 的考验,越来越稳定、高效、准确。具体预测模型、算法上面,延续着业界已公开的论文,并结合阿里业务场景,做适合业务发展需要裁剪实践。
5.4 云端调度
随着云计算的发展,电商混合云部署架构的成熟。几乎所有企业未来都面临云端调度的问题。在云端的资源调度、混合云调度,对系统的协同能力、快速上下线能力提出了更高的要求。2015 年双 11,充分利用了阿里云的公共云计算资源来分担一部分流量,阿里、淘宝、支付宝在今年双 11 做到了这一点,并且扛住了严酷的流量考验。实现了交易上云的关键技术的突破。未来,在云端的交易更加普遍,云端资源调度的技术、经验更加丰富。在技术、经验完善后,电商会分享给业界,让大家享受云带来的低成本、便捷、高效。
附参考文献
[1]http://www.umbrant.com/blog/2015/mesos_omega_borg_survey.html
http://www.infoq.com/cn/articles/comparison-of-mesos-omega-and-borg
[2] Large-scalecluster management at Google with Borg http://research.google.com/pubs/pub43438.html
[3] Mesos: A Platform for Fine-GrainedResource Sharing in the Data Center
https://www.cs.berkeley.edu/~alig/papers/mesos.pdf
Scheduler Http. http://mesos.apache.org/documentation/latest/scheduler-http-api/
Executor Http. http://mesos.apache.org/documentation/latest/executor-http-api/
Internal C++ API. http://mesos.apache.org/documentation/latest/doxygen-style-guide/
Kubernetes on Mesos https://github.com/mesosphere/kubernetes-mesos
[4] Omega: flexible, scalable schedulersfor large compute clusters
http://research.google.com/pubs/pub41684.html
[5]Kubernetes docs
https://github.com/kubernetes/kubernetes/tree/master/docs
http://kubernetes.io/docs/user-guide/
[6]http://www.infoq.com/cn/articles/Kubernetes-system-architecture-introduction
[7]http://www.wired.com/2013/03/google-borg-twitter-mesos/
http://www.cngulu.com/2870.html
[8] A short introduction to queueing theory
[9]资源调度等待开销感知的虚拟机整合
[10] NilabjaRoy,Abhishek Dubey and Aniruddha Gokhale. Efficient Autoscalling in the Cloudusing Predictive Models for Workload Forecasting 2011 IEEE 4thInternational on Cloud Computing.
[11] Fei MA,Feng LIU,Zhen LIU.Mulit-objectiveOptimization for Initial Virtual Machine Placement in Cloud Data Center.Journalof Information & Computatioal Science 9:16 2012
[12] Maria Couceiro,Paolo Romano etc. AMachine Learning Approach to Preformance Perdiction of Total Order Broadcast Protocols.SASO10-2008
[13]Xiaoqiao Meng,Canturk Isci etc.Efficient Resource Provisioning in Compute Clouds via VM Mulitplexing. ICAC 10,June 7-11, 2010
[14]Dapeng Dong and John Herert. EnergyEfficient VM Placement Supported by Data Analytic Service. 2013
[15]Berkin Ozisikyilmaz, Machine learningmodels to predict performance of computer system design alternatives. 37thInternational Conference on Parallel Processiong 2008
[16] Performance prediction and optimizationusing Linux cgroup with IO throttle. LinxuCon Europe 2012
[17]Archana Ganapathi etc. Statics-DrivenWorkload Modeling for the Cloud
版权声明: 本文为 InfoQ 作者【阿里技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/6f92ebb3fbdd6e7cf8ad910bb】。未经作者许可,禁止转载。
评论