VM in the Cloud

关于云计算的虚拟机背景知识

主要参考文献 ”Protean: VM Allocation Service at Scale (OSDI'20)“

Inventory

Inventory 的中文翻译是库存资源池。但其含义远比字面意思丰富。核心内涵包括:

 

一个global inventory 通常是层次结构的,以Azure为例,就包含了region, zone, datacenter, cluster, rack, machine的层级,如下图所示:

zone和datacenter的规模通常没有严格上限,从小到大都有。

但也有一些特征:

 

Tenant

仍然以Azure为例,用户以服务请求(Service Request)的形式指定其需求。一个服务请求由一个或多个 VM 请求组成,这些 VM 请求被归为同一个租户 (tenant)。

租户服务模型(the tenant service model) 表达了这些 VM 之间的关系和所施加的约束。只有当租户中所有请求的 VM 都成功分配时,分配才算成功(即 成组调度 / gang-scheduling)。

 

 

Workload in the Cloud

 

 

Takeaway

 

 

Protean AA

Protean是微软在OSDI'20上发布的论文,并服役于Azure,其本质是一个调度器。Protean 的主要职责是:在满足底层服务模型中明确指定的需求和约束条件,以及其他内部运营考量的前提下,为分配请求中的每个 VM 找到一个物理位置(机器)。

为了应对大量请求负载,Protean 使用了多个 分配代理(Allocation Agents, AAs) 并行运行。每个代理都能感知整个资源库存(inventory),并可以从中选择任意符合条件的机器来承载一个 VM。资源库存的权威状态存放在持久化存储中。每个 AA 维护着自己的库存视图,该视图会通过周期性更新,以及在分配或库存相关事件发生时进行更新。

Metrics and Constraints

Protean 关注多个与性能和分配质量相关的指标。关键指标包括:

需要注意的是,延迟本身并非独立关键指标(尽管对于大型租户可能会变得过高)。然而,更低的延迟有助于提高吞吐量。直观上,当延迟较低时,请求可以由较少的分配代理(AAs)处理,从而减少冲突,可能获得更高的吞吐量。此外,更低的延迟还降低了单个 AA 与库存真实状态偏离的概率,从而提高分配质量。

当然,上述三个指标都依赖于库存规模。库存越大,延迟和吞吐量的挑战越大,但接受请求变得相对容易。我们也关注计算资源的高效利用;在 §6 中,我们将正式定义与利用率相关的指标。

 

 

Requirements and Constraints

 

Allocation Rules

如上所述,Protean 必须同时考虑多种因素:

由于涉及的维度众多,Protean 的分配逻辑被组织为一套 规则(rules)。这些规则决定了每个 VM 将被分配到哪台机器。对于包含 k 个 VM 的服务请求,规则逻辑将被调用 k 次。

 

规则被分为 验证规则(validator rules)偏好规则(preference rules)

规则被组织为 两级层次结构——先是集群选择规则(cluster selection rules),然后是机器选择规则(machine selection rules)。截至2020年,系统中总共有大约一百条规则。

集群选择规则 通过将机器选择规则的作用范围限制在区域内的少量集群,从而有效降低了选择过程的时间复杂度。由于集群是同质的(见 §2),我们实现了若干集群 验证规则(cluster validator rules),用于筛选出与 VM 请求无关的集群(例如,需要 GPU 的 VM 只能部署在包含 GPU 的集群上)。此外,还使用了一些集群 偏好规则(cluster preference rules) 来对有效集群进行排序(例如,为了平衡集群间的可用容量,我们倾向于选择空闲更多的集群)。

筛选 + 排序 + Top-K

基于这些规则,Protean 会选择 质量最高的 k 个集群,其中 k ∈ [8, 16] 是可配置参数;用于机器选择规则的库存(inventory)将由这些集群中的机器组成。参数 k 的设定基于一个权衡:在提供足够多的机器以做出高质量决策与保持合理延迟之间进行折中。

接下来,机器选择规则 同样由验证规则和偏好规则组成:

当有多个机器同样符合条件时,会通过随机化的 平局打破规则(randomized tie-breaking rule) 从中选择一台机器用于 VM 的物理分配。

 

验证规则(Validator rules)

每条验证规则实现一个布尔方法 IsValid(x, v),用于判断对象 x 是否是放置 VM v 的有效候选对象;根据具体规则,对象可以是 集群(cluster)机器(machine)。验证规则用于将库存(inventory)中的对象集合剪枝为仅包含 有效候选对象 的子集。

示例

  1. AreNodeResourcesValid(x, v):检查机器 x 是否有足够的可用资源以容纳 VM v。如果所有资源维度(CPU、内存、磁盘等)都能满足,则方法返回true

  2. IsTypeSupported(x, v):检查集群 x 是否兼容 VM v 对应的类型。

 

偏好规则(Preference rules)

偏好规则用于量化每个候选对象 x(根据具体规则可以是 集群机器)与 VM 的匹配程度。每条偏好规则 r 针对特定考量(例如打包质量、负载均衡、集群/机器质量等)通过数值评分 Sr(x,v) 来评估。我们使用的约定是:分数越低越好

示例

  1. BestFit(x, v):分配一个分数

Sr(x,v)=iwi(ai(x)di(v))Sr(x,v)=iwi(ai(x)di(v))Sr(x,v)=iwi(ai(x)di(v))

其中 ai(x) 表示机器 x 在“资源” i(例如 CPU 核心数、内存、SSD)上的可用量,di(v) 表示 VM 在该资源上的需求,wi 是该资源的权重,用于量化其稀缺性(直观上,wi 越高,资源越稀缺)。分数越低表示机器越适合该 VM,因为资源被更合理地打包;类似的打包启发式方法在文献 [39] 中也有提出。

  1. PreferNonEmptyMachines(x, v):该规则偏好使用非空的机器,主要目的是提高打包质量。

  2. PreferEmptierClusters(x, v):该规则量化集群 x 中空闲核心的数量。其核心思想是平衡集群之间的可用容量,从而降低集群容量被耗尽的概率。这在多个方面都很重要,例如,某些客户要求集群内亲和性,如果集群已满,则无法进行横向扩展。

 

Accounting for Multiple Rules

验证规则(validator rules) 的序列会筛选掉不适合该 VM 的对象(集群或机器)。Protean 设计中的一个主要挑战是:如何处理多个偏好规则(preference rules)?

这里的固有问题在于,不同规则表示不同且难以直接比较的偏好:

 

Architecture

运行机制

Protean 采用多个同时运行的 分配代理(AAs),遵循乐观并发模型。

 

AAs 的数量根据区域内瞬时峰值需求确定,而每台机器上的 AAs 数量取决于每个 AA 的内存占用。每个 AA 基于自身的(可能是过时的)库存视图做出分配决策,在成功处理请求后,会尝试将结果提交到 复制存储(replicated store)。复制存储负责冲突检测,并将提交序列化到同一节点(不同节点的提交可以并行处理)。此外,它存储所有由 AA 的 VM 分配决策修改的库存信息。复制存储是最新分配相关库存状态的权威来源,并通过 发布-订阅(pub/sub)服务 发布所有变化。库存中不受分配决策影响的变化(如机器健康状况或能力变化)也通过 pub/sub 服务发布。AAs 主要通过 pub/sub 服务产生的更新来获知库存变化。此外,在提交因冲突失败时,它们还会在失败通知中获知冲突机器的最新分配相关信息。

 

服务分配工作流程

一个服务请求可能包含多个 VM 请求,这些请求由单个 AA 按顺序处理。算法 1 总结了 Protean 如何处理服务请求。

提交阶段与前面的阶段流水线并行进行,这样 AA 可以在提交过程中继续处理下一个请求。

 

 

Implementation

在本节中,我们将介绍 缓存框架(caching framework),它显著加速了 ASSIGN_MACHINE_TO_VM 过程(见 §5.1–5.2)。我们还将讨论 灵活的冲突检测与减少机制(见 §5.3)。

预备知识

为了做出高质量的分配,AA 最初将库存中的所有机器都视为候选对象。

集群选择(Cluster selection) 如 §3.2 所述,AA 在选择过程中首先对 集群 进行筛选和排序,而不是直接对机器操作。由于一个区域(zone)最多只有几百个集群,因此对集群的筛选和排序非常快(通常只需几毫秒)。因此,集群选择阶段不需要额外的优化(例如缓存过去的选择结果)。该阶段的输出是 最佳的 8 到 16 个集群;这些集群中的机器(通常约 10–15k 台)将成为机器选择阶段的候选对象。

机器选择 —— 基本复杂度(Machine selection – basic complexity) 回顾一下,机器选择逻辑首先通过对每台机器评估所有 验证规则(validator rules),将候选机器集合裁剪为有效机器集合。然后,它根据每台机器承载 VM 的适合度(§3.3)构建基于比较的全序排序。最后,从最佳机器集合中随机选择一台机器。

构建评估结果(即有效机器的有序列表)所需的运行时复杂度为:

Complexity=Ni=1K1Tv(i)+NlogN(i=1K2Tp(i))

其中:

如果 AA 对每个请求都从头构建评估结果,对于几千台机器以上的情况,会超出所需的延迟限制。

先筛选(验证),再比较排序(偏好)。因此是串行累加的复杂度。

 

缓存动机(Motivation for caching) (1)首先,我们观察到 请求具有局部性(Locality in requests)

 

(2)第二个观察是 库存状态变化缓慢

 

这些特性表明,我们可以通过 缓存和重用上一次执行的评估状态,大幅减少机器选择逻辑的计算量。直观上,唯一需要的计算是 更新状态以反映自上一次执行以来库存变化的影响

 

Caching for Efficient Machine Selection

每个 AA 都维护一组 缓存对象,这些对象共同保存了机器选择所需的信息。

Caching Rule State

 

 

 

 

Caching Rule Evaluation State

缓存规则对象有助于显著降低 Tv(i)Tp(i)的开销。然而,如果没有其他优化,我们仍然需要承担 NlogN 的排序复杂度。因此,我们引入了额外的对象,称为 RuleEvaluation 对象

一个 RuleEvaluation 对象本质上保存了针对特定特征值向量(traitvector,见 §5.1)的完整评估状态。该状态包括评估结果(已排序的机器列表)以及与评估相关的规则对象的引用,这些规则对象的特征值与整个向量中的对应值匹配。

在为新的特征值向量计算评估结果后,会创建一个 RuleEvaluation 对象(该特征值向量用作对象的标识符)。随后,该对象将被重用于所有映射到该标识符的请求。

 

更新 RuleEvaluation 对象

与规则对象类似,缓存的 RuleEvaluation 对象在使用前也需要更新到最新状态。然而,与规则对象不同的是,RuleEvaluation 对象使用一个通用的 Update 方法,其目标是根据状态变化的机器更新评估结果。该方法执行流程如下:

  1. 调用缓存规则对象的 Update 方法,将它们更新到最新状态;

  2. 将状态发生变化的机器从评估结果中移除;

  3. 对这些机器运行 validator rules,以确定哪些机器是有效的;

  4. 将有效机器重新插入到有序列表中,并更新其位置。

由于每次插入操作的时间复杂度为 NlogN,因此 Update 方法的运行时复杂度为 MlogN,其中 M 是状态发生变化的机器数量。这显著降低了复杂度,因为通常 MNM 大约为几十台)。

RuleEvaluation 对象被缓存于另一个固定大小的内存池中,并遵循 LRU 驱逐策略

 

示例

考虑一个示例场景,其中每个请求可以有两个特征:X{x1,x2}Y{y1,y2};分配逻辑通过两个规则表示:R1 依赖于特征XYR2 依赖于 X​。

总体而言,共创建了两个 RuleEvaluation 对象,分别对应两个特征值向量{x1,y1},{x1,y2}。它们共用一个规则 R2 的对象,但规则R1 使用两个独立对象。

 

Additional Cache Hierarchies

多个规则往往依赖于状态的相同部分。例如,多个规则需要跟踪机器是否为空(例如,BestFit 规则以及一个尝试在机架之间平衡容量的规则)。对于这种情况,我们将状态的共享部分封装在一种 Shared-Cache(共享缓存) 类型中,多个规则可以引用它。

与 Rule 类似,Shared-Cache 也实现了 Update 方法,并声明它所依赖的任何请求特征。Shared-Cache 在减少内存使用方面发挥了重要作用。这些对象被缓存到它们自己的固定大小的内存池中。

如前所述,一个缓存对象可能依赖于其他缓存对象。因此,规则选择引擎会确保在更新某个对象之前,先更新其所有依赖项。

我们的缓存层次结构嵌入了一些理想特性。例如,当一个新的 RuleEvaluation 对象被创建时,它通常可以依赖于已有的规则对象和 Shared-Cache 对象。

 

Efficiently Updating the Cache

跟踪与更新机制

回顾一下,每个 AA 都维护着自己私有的缓存。由于每个缓存对象在原则上都可以在使用之前更新,因此对象可能会处于不同程度的陈旧状态。为了实现无缝更新,每个 AA 都维护一个 日志(journal),用于跟踪库存中任何机器的变化。该日志维护一个全局修订号,每次更新时都会递增。此外,日志只存储每台机器的最新状态。每个缓存对象都会记录它所见过的最高修订号,该修订号对应于该对象已消费的最新库存更新。对象通过读取日志中修订号更高的记录来自行更新。因此,更新操作的运行时复杂度与被修改的机器数量成正比,而不是整个库存规模。在进行评估时,AA 会更新日志,记录其正在做出的每个 VM 放置决策。此外,AA 还会在评估之间更新日志,方法是处理从 发布/订阅服务(pub/sub service)放置存储(placement store) 入队的传入更改。

 

后台更新

一个最新的缓存可以在几毫秒内处理完一个请求,只需提取出最佳机器即可。然而,如果缓存不是最新的,那么 即时缓存更新 的时间可能会占据 VM 请求总延迟中的很大一部分。尽管如此,由于系统中存在多个 AA,它们的配置足以应对少数峰值负载时期,因此大多数时间处于空闲状态。因此,当某个 AA 没有请求需要处理时,它会被 用来机会性地更新缓存(从 RuleEvaluation 缓存对象开始,并递归地向下进行)。