《
Nova创建虚拟机实例过程简述》文章中,讲述了创建虚拟机实例的一个整体过程,现在,我们要开始着重分析和研究compute-api将请求发送到Scheduler后,Scheduler是如何实现初始调度工作的。
最后调用 self.driver.schedule_run_instance(context,***)
这里配置文件中,Scheduler_driver的默认值
default = nova.scheduler.filter_scheduler.FilterScheduler
上述通过_scheduler来调度产生最终筛选好的compute node,即weight_hosts(当然,它返回的是一个列表)
再来看上面的函数,我们打开/nova/shceduler/host_manager.py文件,找到对应的get_all_states()方法
(2)在获取到了hosts列表之后,接下来的工作当然是图中的第2步,Filter,函数调用如下:
将filter_proprerties,hosts作为参数传到get_filtered_hosts()函数中去,得到Filter之后的hosts
(4)最后返回选择好的主机给compute去执行
在/nova/scheduler/filetr_scheduler中,将weight_hosts再通过另外的函数去执行。
下面有很多比较重要的参数,比如filter_properties,scheduler_hints,request_spec等等,我会通过另外的博文来说明这几个参数到底指代的是什么东西,这里不做讨论。另外,Scheduler的具体细节也是以后再做介绍
好了,一个简单的Scheduler 调度过程讲述完毕,望大神指教
关于Scheduler的作用资料很多,我下面就引用下大神的一段话(转)
“Nova-Scheduler主要完成虚拟机实例的调度分配任务,创建虚拟机时,虚拟机该调度到哪台物理机上,迁移时若没有指定主机,也需要经过scheduler。资源调度是云平台中的一个很关键问题,如何做到资源的有效分配,如何满足不同情况的分配方式,这些都需要nova-scheduler来掌控,并且能够很方便的扩展更多的调度方法,可能我需要虚拟机调度到空闲的机器,可能还需要将某类型的虚拟机调度到固定的机架等等”
下面让我们来看一看具体的调度过程。
(一)Scheduler启动相关分析
(1)compute-api通过一层层调用,最后调用/nova/compute/manager.py的run_instance(),如下图:
- <strong> </strong>#启动虚拟机
- def run_instance(self, context, request_spec, admin_password,
- injected_files, requested_networks, is_first_time,
- filter_properties, legacy_bdm_in_spec=True):
- """Tries to call schedule_run_instance on the driver.
- Sets instance vm_state to ERROR on exceptions
- """
- instance_uuids = request_spec['instance_uuids']
- """Compute-related Utilities and helpers."""
- #compute_utils = utils
- #EventReoprt()是一个类
- with compute_utils.EventReporter(context, conductor_api.LocalAPI(),
- 'schedule', *instance_uuids):
- try:
- #调用driver(filter_scheduler.py)中的schedule_run_instance()
- return self.driver.schedule_run_instance(context,
- request_spec, admin_password, injected_files,
- requested_networks, is_first_time, filter_properties,
- legacy_bdm_in_spec)
最后调用 self.driver.schedule_run_instance(context,***)
我们再来看看,这个driver是什么东西
- scheduler_driver_opt = cfg.StrOpt('scheduler_driver',
- default='nova.scheduler.filter_scheduler.FilterScheduler',
- help='Default driver to use for the scheduler')
注意,在早些版本的时候,这个默认值都是MultiScheduler,现在nova-volumn用一个新的项目cinder代替了,所以,也就不采用原来的那个方案了。直接driver= FilterScheduler
(2)通过self.driver.schedule_run_instance(context,***)调用,我们转到了/nova/scheduler/filter_scheduler.py文件,看到class FilterScheduler类。
- def schedule_run_instance(self, context, request_spec,
- admin_password, injected_files,
- requested_networks, is_first_time,
- filter_properties, legacy_bdm_in_spec):
- """This method is called from nova.compute.api to provision
- an instance. We first create a build plan (a list of WeightedHosts)
- and then provision.
- Returns a list of the instances created.
- """
- payload = dict(request_spec=request_spec)
- self.notifier.info(context, 'scheduler.run_instance.start', payload)
- instance_uuids = request_spec.get('instance_uuids')
- LOG.info(_("Attempting to build %(num_instances)d instance(s) "
- "uuids: %(instance_uuids)s"),
- {'num_instances': len(instance_uuids),
- 'instance_uuids': instance_uuids})
- LOG.debug(_("Request Spec: %s") % request_spec)
- #*******************开始调用_schedule方法,来实现调度******************************#
- #关键调用
- #通过下面的_schedule()进行调度,返回list_host
- weighed_hosts = self._schedule(context, request_spec,
- filter_properties, instance_uuids)
- #**********************************************************************************#
上述通过_scheduler来调度产生最终筛选好的compute node,即weight_hosts(当然,它返回的是一个列表)
(二)让我们看看_scheduler()到底做了什么?
_scheduler()方法的标准定义如下:
""Returns a list of hosts that meet the required specs,ordered by their fitness."" ------定义简单明了
FilterScheduler的过程分为两步=Filter+weight,如下图所示
这一个图是官方提供的非常经典的主机过滤过程流程图,照着这个图,我们再去理解代码的含义会相对简单一点。
过程分为1->2->3,最后黄色的host即为_schedule的返回值,下面是对该图过程的具体解释
(1)先解决途中1的hosts是从哪里来的,在_schedule中,我们看到了如下的调用:
- <span style="font-family:Arial,Helvetica,sans-serif">hosts = self.host_manager.get_all_host_states(elevated)</span>
- def get_all_host_states(self, context):
- """Returns a list of HostStates that represents all the hosts
- the HostManager knows about.
- Also, each of the consumable resources
- in HostState are pre-populated and adjusted based on data in the db.
- """
- # Get resource usage across the available compute nodes:
- #通过下面的语句,在数据库中得到所有的计算节点信息
- #IMPL.compute_node_get_all(context, no_date_fields)
- compute_nodes = db.compute_node_get_all(context)
(2)在获取到了hosts列表之后,接下来的工作当然是图中的第2步,Filter,函数调用如下:
- hosts = self.host_manager.get_filtered_hosts(hosts,
- filter_properties, index=num)
将filter_proprerties,hosts作为参数传到get_filtered_hosts()函数中去,得到Filter之后的hosts
(3)第一次筛选过后,要开始计算每个host的权值,也就是图中的第三步。
- weighed_hosts = self.host_manager.get_weighed_hosts(hosts,
- filter_properties)
(4)最后返回选择好的主机给compute去执行
在_schedule函数中:
- return selected_hosts
- weighed_hosts = self._schedule(context, request_spec,
- filter_properties, instance_uuids)
下面有很多比较重要的参数,比如filter_properties,scheduler_hints,request_spec等等,我会通过另外的博文来说明这几个参数到底指代的是什么东西,这里不做讨论。另外,Scheduler的具体细节也是以后再做介绍