跳转到: 导航, 搜索

分布式调度器

  • Launchpad 入口: NovaSpec:bexar-distributed-scheduler
  • 创建: 2010-11-16
  • 贡献者: Eric Day, Paul Voccio, Vish Ishaya, Ed Leafe

总结

最初这被命名为“分布式数据存储”,但在设计峰会讨论后,我们意识到将其作为可选调度器来实现会更好。最初的讨论建议要求每个worker/调度器级别使用本地数据存储,例如 SQLite,并且不再支持使用中心数据库,例如 PostgreSQL 或 MySQL。这演变为它实际上是调度器实现问题,而不是需要在整个架构中强制要求的东西。这将允许两种类型的配置都成为可能。简单的安装可以使用默认调度器和中心数据存储,而复杂的、多区域安装将使用分布式调度器,使用数据的本地副本,并通过数据聚合通道推送数据。为了实现这一点,nova核心需要提供适当的类和功能来编写这样的调度器。保持可选性将使中心数据存储成为可能,但很可能会有一些数据重复,并且如果使用SQL数据存储,则将不会使用外键和其他直接引用。要达到一个完全功能的分布式调度器,需要多个步骤,本规范和相关的Launchpad蓝图将描述需要完成的工作。

发布说明

这些变更不会影响使用外部HTTP API的用户。部署nova的人将可以选择运行一个可以在多个层级上运行以跨越各种区域(逻辑或地理)的不同调度器。默认调度器可能会从当前状态更改为比单个worker更简单,甚至根本没有worker。因此,如果您正在升级一个简单的安装,您可能不再需要运行 bin/nova-scheduler。还可能存在数据库模式更新,这将需要迁移,但这些将在实施过程中确定。

原理

大规模部署需要更强大的调度器和数据存储。我们还需要一个可以帮助最大限度地减少任何受损节点的范围的调度器和系统。该系统还需要在某些节点可能关闭的情况下运行,包括容忍网络分区并在系统任何部分发生故障时最大限度地减少停机时间。允许所有worker(尤其是compute)完全访问中心数据存储对于某些部署来说是不可接受的。

用户故事

Rackspace 目前使用分布式模型来实现可扩展性和高可用性,这些相同的原则需要引入 Nova,使其适合大规模部署。

前提条件

我们正在使用持久消息队列,消息不会丢失。在发生严重故障导致消息丢失的情况下,某些操作或API请求可能会丢失,需要重试。

设计

需要先采取一些步骤才能支持编写分布式调度器。它们是

  • 目前,从HTTP API模块到compute/volume/network处理类的代码路径中存在一些重复。HTTP API模块应该围绕着相关服务模块(compute、network 或 volume)内部的明确定义的内部API的非常薄的层。我们必须尽可能地将逻辑从 nova.api 推送到 nova.compute/network/volume。
  • 更改API请求处理方式,使API服务器不写入任何数据。操作应该推送到相关的worker。例如,在run_instances时,我们希望compute worker成为发起写入数据存储的进程。
  • 重构当前调度器,使其不需要worker,并将更多调度选项推送到调度器(而不是compute/volume/network)。运行worker的依赖性应该取决于您选择的调度器。有些调度器将为零,而另一些可能有多层。
  • 引入允许从worker通过调度层和API节点到核心Nova类的进行数据聚合的机制。各种调度器实现然后可以选择使用这些机制来构建适合其需求的架构。
  • 通过使用数据聚合能力并引入通过消息队列的功能来消除对中心数据存储的需求,用于系统中需要从其他来源查找信息的部分。这意味着某些配置可以保留其需要的数据的本地数据存储(可能使用SQLite),而不是所有worker/API服务器依赖于中心数据库,例如 PostgreSQL 或 MySQL。
  • 重构rpc模块消息传递,以允许使用签名消息,以便队列消费者可以验证来源。这对于安全考虑是必需的。
  • 使用现有和新的核心Nova功能编写默认分布式调度器。

实现

为了简单起见,讨论将仅限于调度一个新的compute实例。volume和network的过程将是类似的,但要简单得多。

我假设 OpenStack 部署了嵌套区域。在具有单个区域的简单部署中,中间结果的聚合将不适用,所有这些都将发生在单个调度器中。

为了创建一个新的实例,我们需要能够找到一个能够容纳新实例的compute主机。另一种说法是,该主机满足某些要求:它必须能够托管所需的操作系统;它必须有可用的RAM和磁盘空间等。我将这些标准称为要求

此外,可能还有其他标准,它们不是绝对必需的,但可用于确定将新实例放置在一个合格主机上而不是另一个主机的期望值。例如,我们可能希望将客户的新实例放置在一个该客户尚未实例的主机上,以便在硬件故障时分散不利风险。虽然这是期望的,但如果唯一可用的主机确实具有另一个客户的实例,我们仍然希望创建请求的实例。我将这种类型的标准称为权重,它们将用于对新实例的主机适用性进行加权。部署 OpenStack 的每个公司很可能都有自己的加权标准。

当前区域的设计将使主机定期将其状态发布到其ZoneManager(调度器服务的一个组件),该组件将维护该信息。它能够呈现聚合答案(例如,“您可以创建Windows实例吗?”)基于其主机,并返回有关单个主机的相关信息。更高层次的区域(即没有主机的区域)将聚合其子区域的结果。例如,如果任何子区域都可以创建Windows实例,则父区域将报告它具有Windows功能。

当API收到新的实例请求时,它会将该请求传递给该区域的调度器服务。如果该区域具有子区域,则该请求将传递到每个子区域,直到到达区域树的“最低”级别。在沿着此区域遍历的每个步骤中,ZoneManager将比较需求与其功能;如果没有匹配项,则意味着其“下方”的任何主机都无法处理该请求,因此它将返回一个空列表。否则,它会将请求转发到子区域,并返回其响应的聚合。

当一个区域具有主机时,它将运行调度器算法,该算法将对主机数据进行操作,以消除无法满足要求的那些主机,然后根据权重对满足要求的那些主机进行排序。由于一个区域可以管理大量主机,因此返回所有匹配的主机,尤其是那些权重较低的主机,将效率低下。将有一个配置选项来设置要返回的主机数量,我们在这里称之为N

父区域将从每个子区域接收一个列表,如果它也有主机,则可能也有自己的列表。它的调度器将连接这些列表,并对新的更大的列表运行相同的加权算法,然后将前N个主机返回给其父区域。这会重复,直到到达发起请求的区域。然后它将向列表中的第一个条目发出创建请求;这要么成功,要么失败。如果失败,则迭代列表,直到成功或到达末尾。

这种分布式设计将随着部署规模的增长而很好地扩展,因为可以添加新的区域来逻辑地分组,从而分解跨整个部署评估/加权潜在主机的负载。将每个区域的响应限制为固定数量的主机也将有助于最大限度地减少区域之间的流量。

虽然这种设计试图足够灵活,以便每个部署都可以确定他们希望如何选择新实例的主机,但有一个潜在的问题:Zone Master对象拥有的主机信息只是主机告诉它的;它不会查询主机。换句话说,调度器需要确保主机在定期更新期间发送了评估其算法中所需的主机信息。主机发送的一些数据是恒定的:它将由诊断、日志记录、状态更新等需要,但有些将取决于特定的调度器选择算法。我正在寻找一种以单一位置定义这些属性的方式,该位置可以从调度器和compute服务导入,以便compute节点可以读取这些属性并将它们的值发布到其ZoneManager,并且调度器服务也可以这样做。细节仍需确定。

UI 变更

对最终用户来说不应有任何可见的变化,所有这些工作都将发生在API服务器之后。

代码变更

代码更改应隔离到API、compute、rpc和scheduler模块。它也可能涉及network和volume模块,以便将数据推送到那里。它不应涉及每个worker处理请求的方式(vm/network/volume管理),而更多的是处理它们之间的数据和消息的方式。

迁移

在实施接近beta时提供。

测试/演示计划

将随着代码的开发提供单元测试。在有基础设施进行测试时,将添加集成和大规模测试。

未解决的问题

无。

BoF 议程和讨论

Bexar设计峰会的相关会议有以下笔记

http://etherpad.openstack.org/DistributedDataStore http://etherpad.openstack.org/multicluster