nova-compute需要在数据库中存储主机的资源使用情况,包括内存、cpu、磁盘等,以便nova-scheduler获取作为选择主机的依据,这就要求每创建、迁移、删除一个虚拟机,都要更新数据库中相关的内容。
Nova使用ComputeNode对象保存计算节点的配置信息以及资源使用状态。nova-compute为每一个主机创建一个ResourceTracker对象,任务就是更新ComputeNode对象在数据库中对应的表compute_nodes。
有两种更新数据库中资源数据的方式:一是Resource Tracker的Claim机制,二是使用周期性任务(Periodic Task)。
一 Claim机制
当一台主机被多个nova-scheduler同时选中并发送创建虚拟机的请求时,这台主机并不一定有足够的资源来满足这些虚拟机的创建要求。Claim机制即是在创建之前先测试一下主机的可用资源是否能够满足新建虚拟机的需求,如果满足,则更新数据库,将虚拟机申请的资源从主机可用的资源中减掉,如果后来创建失败或者是将虚拟机删除时,会通过Claim加上之前减掉的部分。
#nova/compute/resource_tracker.py
def instance_claim(self, context, instance_ref, limits=None):
if self.disabled:
# compute_driver doesn't support resource tracking, just
# set the 'host' and node fields and continue the build:
self._set_instance_host_and_node(context, instance_ref)
return claims.NopClaim()
# sanity checks:
if instance_ref['host']:
LOG.warning(_("Host field should not be set on the instance until "
"resources have been claimed."),
instance=instance_ref)
if instance_ref['node']:
LOG.warning(_("Node field should not be set on the instance "
"until resources have been claimed."),
instance=instance_ref)
# get memory overhead required to build this instance:
overhead = self.driver.estimate_instance_overhead(instance_ref)
LOG.debug("Memory overhead for %(flavor)d MB instance; %(overhead)d "
"MB", {'flavor': instance_ref['memory_mb'],
'overhead': overhead['memory_mb']})
#如果Claim返回为None,即主机的可用资源满足不了新建虚拟机的需求
#上层函数会调用__exit__()方法将占用的资源返回到主机的可用资源中
claim = claims.Claim(context, instance_ref, self, self.compute_node,
overhead=overhead, limits=limits)
#通过Conductor API更新instance的host、node与launched_on属性
self._set_instance_host_and_node(context, instance_ref)
instance_ref['numa_topology'] = claim.claimed_numa_topology
# 根据新建虚拟机的需求计算主机的可用的资源
self._update_usage_from_instance(context, self.compute_node,
instance_ref)
elevated = context.elevated()
#根据上面的计算结果更新数据库
self._update(elevated, self.compute_node)
return claim
二 Periodic Task机制
在类nova.compute.manager.ComputeManager中有个周期性任务update_available_resource(),用于更新主机的资源数据。
#nova/compute/manager.py
#修饰符periodic_task表示此函数是一个周期性任务,会被周期性调用
@periodic_task.periodic_task
def update_available_resource(self, context):
new_resource_tracker_dict = {}
nodenames = set(self.driver.get_available_nodes())
#更新所有主机数据库中的资源数据
for nodename in nodenames:
rt = self._get_resource_tracker(nodename)
rt.update_available_resource(context)
new_resource_tracker_dict[nodename] = rt
# Delete orphan compute node not reported by driver but still in db
compute_nodes_in_db = self._get_compute_nodes_in_db(context,
use_slave=True)
for cn in compute_nodes_in_db:
if cn.hypervisor_hostname not in nodenames:
LOG.audit(_("Deleting orphan compute node %s") % cn.id)
cn.destroy()
self._resource_tracker_dict = new_resource_tracker_dict
三 小结
这两种更新方式并不冲突,Claim机制是在数据库当前数据的基础上去计算并更新,能够保证数据库里的可用资源及时更新,以便为nova-scheduler提供最新的数据。周期性任务(Periodic Task)是为了保证数据库内的信息的准确性,它每次都会调用Hypervisor获取主机信息,并将这些信息更新到数据库中。