一、回顾
这一小节主要是过滤和权值计算。FilterScheduler的_schedule方法在实现虚拟机调度算法的时,调用了两个很重要的
方法:
(1)调用了HostManager对象的get_filtered_hosts方法 获取可用的计算节点列表。
(2)调用了HostManager对象的get_weighed_hosts方法 计算可用计算节点的权值。
/nova/scheduler/host_manager.py:
def __init__(self):
...
self.filter_handler = filters.HostFilterHandler()
filter_classes = <strong><span style="color:#ff0000;">self.filter_handler</span></strong>.get_matching_classes(
CONF.scheduler_available_filters)
self.filter_cls_map = {cls.__name__: cls for cls in filter_classes}
self.filter_obj_map = {}
self.default_filters = self._choose_host_filters(self._load_filters())
self.weight_handler = weights.HostWeightHandler()
weigher_classes = <strong><span style="color:#ff0000;">self.weight_handler</span></strong>.get_matching_classes(
CONF.scheduler_weight_classes)
....
HostManager类的初始化方法中,分别调用HostFilterHandler对象和HostWeightHandler对象get_matching_classes
方法加载可用的过滤器类和权值类。过滤器类和权值类是实现get_filtered_hosts和get_weighed_hosts方法的基
础。
二、get_filtered_hosts方法
HostManager对象的get_filtered_hosts方法定义如下:(获取可用的计算节点列表)
class HostManager(object):
def get_filtered_hosts(self, hosts, filter_properties, filter_class_names=None):
...
#获取过滤器列表
filter_classes = self._choose_host_filters(filter_class_names)
...
#返回过滤后的主机(计算节点)列表
return self.filter_handler.get_filtered_objects(filter_classes,
hosts, filter_properties)
(1)、为了确定计算节点是否可用,Nova Scheduler定义了多个过滤器,每个过滤器检查计算节点的某一种属性。只
有通过所有过滤器检查的计算节点才是可用的计算节点。
(2)、上面的方法首先调用_choose_host_filters获取过滤器类列表。然后调用filter_handler变量的
get_filtered_objects方法使用过滤器检查计算节点是否可用。另外get_filtered_hosts方法还可以通过参数
filter_properties传入force_hosts和ignore_hosts两个变量(主机淘汰规则)。
三、HostManager类的_choose_host_filters方法
_choose_host_filters方法:HostManager类的_choose_host_filters方法的功能是获取过滤器类列表。
class HostManager(object):
def _choose_host_filters(self, filter_cls_names):
#如果外部没有传入filter_cls_names参数,则使用默认的过滤器
if filter_cls_names is None:
filter_cls_names = CONF.scheduler_default_filters
#将filter_cls_names封装成列表
if not isinstance(filter_cls_names, (list, tuple)):
filter_cls_names = [filter_cls_names]
good_filters = []
bad_filters = []
#遍历所有配置的过滤器
for filter_name in filter_cls_names:
found_class = False
#遍历所有注册的过滤器
for cls in self.filter_classes:
#如果filter_name对应的过滤器在注册的过滤器列表中,则认为是好过滤器
if cls.__name__ == filter_name:
good_filters.append(cls)
found_class = True
break
#如果filter_name对应的过滤器不在注册的过滤器列表中,则认为是坏过滤器
if not found_class:
bad_filters.append(filter_name)
...
return good_filter
遍历filter_cls_names参数中所有的过滤器,从中提取好的过滤器,所谓好的过滤器就是指
这个过滤器之前被注册
过。这个注册过程在HostManager类的初始化方法中通过调用filter_handler对象的get_matching_classes方法注册
可用的滤波器,get_matching_classes方法会注册nova.scheduler.filters包下定义的所有过滤器。
注意:
(1) 如果外部没有传入filter_cls_names参数。_choose_host_filters方法会将filter_cls_names设置为默认的过
滤器列表。默认的过滤器列表由nova.conf配置文件的scheduler_default_filters配置项设置。
(2) filter_handler对象的get_matching_classes方法会注册nova.scheduler.filters包下定义的所有滤波器。
四、filter_handler对象的get_filtered_objects方法
1、filter_handler对象的get_filtered_objects方法调用客户指定的过滤器类,检查计算节点是否可用。
get_filtered_objects方法最终返回可用的计算节点列表。
2、filter_handler对象的类型为HostFilterHandler类。HostFilterHandler类继承自BaseFilterHandler类。
get_filtered_objects方法定义在BaseFilterHandler类中:
class BaseFilterHandler(loadables.BaseLoader):
def get_filtered_objects(self, filter_classes, objs, filter_properties):
#遍历每个过滤器
for filter_cls in filter_classes:
#调用过滤器类的filter_all方法
objs = filter_cls().filter_all(objs, filter_properties)
return list(objs)
filter_classes参数是过滤器类型列表,objs参数是待过滤的计算节点列表,filter_properties参数是客户定制的
过滤参数。
3、get_filtered_objects方法依次调用了每个过滤器对象的filter_all方法。每个过滤器对象的filter_all方法返
回一个迭代器对象,该迭代器包含通过该过滤器检查的主机列表。
4、每个过滤器对象都继承字BaseHostFilter类,BaseHostFilter类继承自BaseFilter类。filter_all方法定义在
BaseFilter类中,定义:/nova/filters.py
class BaseFilter(object):
def filter_all(self, filter_obj_list, filter_properties):
for obj in filter_obj_list:
if self._filter_one(obj, filter_properties):
yield obj
filter_obj_list待过滤的计算节点列表, filter_properties客户定制的过滤参数
(1)、filter_all方法对每个主机都掉用_filter_one方法,如果返回True,则返回该主机的引用。BaseFilter类中的
_filter_one方法始终返回True。BaseHostFilter类重载_filter_one方法,调用自身的host_passes方法。
(2)、BaseFilter类中的_filter_one方法:
class BaseHostFilter(filters.BaseFilter):
def _filter_one(self, obj, filter_properties):
return self.host_pass(obj, filter_properties)
过滤器类的内部逻辑定义在host_passes方法中。参数:待过滤的主机引用,客户定制的过滤参数
对于一个主机,如果过滤器的host_passes方法返回True,则主机通过该过滤器的检查,认为是可用的。
五、举例说明
更好的理解过滤器如何工作,着重分析ComputeFilter过滤器的host_passes方法的定义:
class ComputeFilter(filters.BaseHostFilter):
def host_passes(self, host_state, filter_properties):
"""Returns True for only active compute nodes."""
#节点的服务信息
service = host_state.service
#如果节点的服务不是活动状态或者被禁用,则不通过检查
if service['disabled']:
LOG.debug("%(host_state)s is disabled, reason: %(reason)s",
{'host_state': host_state,
'reason': service.get('disabled_reason')})
return False
else:
if not self.servicegroup_api.service_is_up(service):
LOG.warning(_LW("%(host_state)s has not been heard from in a "
"while"), {'host_state': host_state})
return False
return True
1、ComputeFilter过滤器主要调用servicegroup_api的service_is_up方法,
检查计算节点上的Nova Compute服务是
否处于激活状态。
2、openstack中,任何一个服务都会有一个定时任务,定时在数据库中更新自己的状态。servicegroup_api的
service_is_up方法(/novaservicegroup/api.py)会查询数据库,检查服务最近的更新时间。没有更新,认为服务已
经关闭。
注意:ComputeFilter是一个最基本的过滤器。如果一个节点上连Nova Compute服务没有启动,根本谈不上创建虚拟
机。
总结:HostManager对象的get_filtered_hosts方法的工作流程。
1、HostManager对象的get_filtered_hosts方法首先调用HostManager对象的_choose_host_filters方法获取过滤器
类列表。然后使用HostManager对象的get_filtered_objects方法使用过滤器检查计算节点是否可用。
2、_choose_host_filters方法依次检查filter_cls_names参数中的过滤器名,如果过滤器名对应的过滤器被预先注
册过,则认为是好的过滤器。最终,_choose_host_filters方法会返回所有好过滤器列表。
如果外部没有指定filter_cls_names参数,_choose_host_filters会使用nova.conf配置文件默认过滤器。
3、HostManager对象的get_filtered_objects方法依次调用每个过滤器对象的filter_all方法。返回的是通过该滤波
器的主机列表。
4、过滤器对象的filter_all方法对每个待过滤的主机调用filter_one方法,如果返回True,则代表主机通过检查。
5、filter_one方法调用host_passes。过滤器对象的主要逻辑都定义在host_passes方法中。