1 nova-schedule概述

Openstack中Scheduler脚本启动流程和调度流程分析初步

看这幅图,nova中包含了非常多的组件,nova-api,nova-compute,nova-schedule等等。我们要研究的是nova-schedule这个组件。

nova-schedule组件的功能其实很简单,它从Queue中取出一个虚拟机实例的请求,并决定这个虚拟机实例应该运行在哪个计算结点(compute server host)上。但是,nova-schedule组件会渐渐变得复杂,因为它需要考虑当前的云基础平台的运行状态,并使用某些复杂的算法来达到资源的有效利用。为了这个目的,nova-schedule实现了可插拔的架构,让我们可以选择已有的算法或写出自己的算法。

2 nova-scheduler启动脚本分析

接下来以nova-2011.3这个版本的源代码为例,深入分析一下nova调度的流程。

打开nova-2011.3\bin目录下的nova-scheduler文件,看到主函数如下:

if __name__ == '__main__':

utils.default_flagfile()

flags.FLAGS(sys.argv)

logging.setup()

utils.monkey_patch()

server = service.Service.create(binary='nova-scheduler')

service.serve(server)

service.wait()

nova-scheduler文件是一个python脚本,其作用就是启动nova-scheduler组件。下面我们来分析一下代码的含义。

2.1 utils.default_flagfile()

尝试寻找设置flagfile(默认是nova.conf)的路径,并加载到输入变量args中。

2.2 flags.FLAGS(sys.argv)

flagfile中的参数放到flag中,不多说明。

2.3 logging.setup()

设置日志。

2.4 utils.monkey_patch()

 

2.5 server = service.Service.create(binary='nova-scheduler')

查看nova.service.py文件可以看到,create函数的原型如下:

@classmethod

def create(cls, host=None, binary=None, topic=None, manager=None,

report_interval=None, periodic_interval=None)

可见create函数是Service的类函数。

在create函数中,初始化了将要创建的Service类的对象的一些参数,包括:

1.将host设置为

socket.gethostname(),即当前节点的主机名。

2.topic设置为

topic = binary.rpartition('nova-')[2]即“scheduler”。

3.将manager的类名设置为

manager = FLAGS.get('%s_manager'% topic, None),即"nova.scheduler.manager.SchedulerManager"。

4.将report_interval设置为默认值10秒。report_interval表示节点将状态报告给数据库的时间间隔。

5.将periodic_interval设置为默认值60秒。periodic_interval表示执行周期行任务的周期。

6.调用Service的构造函数。在构造函数中,设置好上述参数,根据manager的名字导入对应的类并创建实例,也就是创建nova.scheduler.manager.SchedulerManager的对象。SchedulerManager是nova.manager.Manager的子类,负责调度器的管理,也就是在nova/scheduler/manager.py文件中设置了默认的调度器。

7.完成Service对象的创建后,返回。

2.6 service.serve(server)

1.service.serve(server)实际上会调用nova.service.Service类自身的start函数来启动服务。所谓启动服务,主要是创建出一个或多个consumer来接收特定Topic的消息队列的消息,并设置好消息监听。

2.调用nova.service.Service类的wait函数,进入等待状态。

2.7 service.wait()

略。

至此nova-scheduler组件就启动了。

3 调度流程

3.1 消息队列

Openstack中使用的消息队列是RabbitMQ,因为篇幅有限,笔者不展开说明消息队列,我们只需要知道,nova中的各个组件都是通过消息队列来通信的,队列可以通过Topic来区分开。

3.2 流程

1.nova-api接到某个请求,例如“run_instance”,nova-api将请求打包后发到Topic为“schedule”的队列。

2.队列接收到消息后,通知消费者(Consumer)。其实就是通过回调函数处理消息,这里的细节比较复杂,回调过程层层传递,我们只需要知道,最终会调用到nova.scheduler.manager.SchedulerManager的_schedule函数。_schedule函数有几个主要的参数:method、contexttopic

3.nova.scheduler.manager.SchedulerManager的_schedule函数中,SchedulerManager首先尝试调用默认调度器的形如“schedule_*”(将*号替换成参数method)的函数,如果没有找到,则调用调度器的schedule函数,选择一台主机。

4 scheduler类图

nova-2011.3版本的scheduler类图如下(由于类图过大,所以下面是简化版):

Openstack中Scheduler脚本启动流程和调度流程分析初步

可以看出,所有的调度器类都继承自Scheduler类。子调度器类应该实现自己的schedule函数,但并不是必须的。从上述流程部分的分析,我们知道,SchedulerManager首先尝试调用默认调度器的形如“schedule_*”(将*号替换成参数method)的函数,如果没有找到,则调用调度器的schedule函数。

5 调度算法

5.1 ChanceScheduler

ChanceScheduler实现的是随机算法。

5.2 SimpleScheduler

5.2.1 schedule_run_instance、schedule_start_instance

内部都调用了_schedule_instance函数,选择已启动的并且运行实例数目最少的主机。

5.2.2 schedule_create_volume

选择已启动的并且具有最小容量的主机。

5.2.3 schedule_set_network_host

选择已启动的并且具有最少网络负载的主机。

5.3 VsaSchedulerLeastUsedHost

继承VSA scheduler,选择具有最少使用能力的主机。

5.4 VsaSchedulerMostAvailCapacity

继承VSA scheduler,选择具有某种类型的最多可用容量的主机。

5.5 AbstractScheduler

5.5.1 filter_hosts

过滤从ZoneManager返回的主机列表,只实现的简单的过滤,即满足请求所需内存的主机都被返回。

5.5.2 weigh_hosts

对主机列表赋予权值。本类中只是将每个主机的权值都赋1,更复杂的实现应由子类完成。

5.6 BaseScheduler

BaseScheduler是创建跨域实例的调度器的基类。

BaseScheduler覆写了父类AbstractScheduler中的filter_hosts和weigh_hosts。

5.6.1 filter_hosts

略。

5.6.2 weigh_hosts

略。

5.7 MultiScheduler

nova-scheduler默认的schedulerMultiScheduler内部包含了多个子调度器。所以原理上它可以根据不同的请求调用不同的调度器。但目前不同的请求调用的都是同一个调度器,即ChanceScheduler,这样的情况在未来应该会改变。

6 修改nova-scheduler(简单)

由于默认的schedulernova/scheduler/manager.py中定义的,我们可以修改这个文件,将默认调度器指向我们自己编写的调度器。

Logo

华为开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐