OpenStack源码分析【2021-11-07】

2021SC@SDUSC

nova/scheduler

简介

在 openstack 中,scheduler 负责从宿主机(运行 nova-compute 的节点)中根据一系列的算法和参数(CPU 核数,可用 RAM,镜像类型等 )选择出来一个,来部署虚拟机(instance)。 scheduler 主要有两个步骤:过滤(filter) + 权重计算(weighting)。(nova scheduler 原理介绍和源码解析
本篇主要分析过滤过程。

源码分析

nova/scheduler/filter_scheduler.py
class FilterScheduler(extended from driver.Scheduler)

1. __ init __()准备工作:

获取一个notifier

获取一个placement客户端(用于更新scheduler的客户端,其中封装了一个预备好的用于API通信的keystone授权适配器,一个包含了计算资源提供者和计算资源存量的缓冲,一个记录上一次更新提供者的集合和特征的时间变量,一个能够访问placement服务的HTTP会话,和一个记录report次数的计数器)

    def __init__(self, *args, **kwargs):
        super(FilterScheduler, self).__init__(*args, **kwargs)
        self.notifier = rpc.get_notifier('scheduler')
        self.placement_client = report.SchedulerReportClient()

2. select_destinations(…)

发了一个“开始选择目的地”的公告

将公告的动向和阶段切换成“开始选择目的地”

调用_scheduler真正干活

发了一个“结束选择目的地”的公告

将公告的动向和阶段切换成“结束选择目的地”

    def select_destinations(self, context, spec_obj, instance_uuids,
            alloc_reqs_by_rp_uuid, provider_summaries,
            allocation_request_version=None, return_alternates=False):
self.notifier.info(
            context, 'scheduler.select_destinations.start',
            dict(request_spec=spec_obj.to_legacy_request_spec_dict()))
        compute_utils.notify_about_scheduler_action(
            context=context, request_spec=spec_obj,
            action=fields_obj.NotificationAction.SELECT_DESTINATIONS,
            phase=fields_obj.NotificationPhase.START)

        host_selections = self._schedule(context, spec_obj, instance_uuids,
                alloc_reqs_by_rp_uuid, provider_summaries,
                allocation_request_version, return_alternates)

        self.notifier.info(
            context, 'scheduler.select_destinations.end',
            dict(request_spec=spec_obj.to_legacy_request_spec_dict()))
        compute_utils.notify_about_scheduler_action(
            context=context, request_spec=spec_obj,
            action=fields_obj.NotificationAction.SELECT_DESTINATIONS,
            phase=fields_obj.NotificationPhase.END)
        return host_selections

_scheduler将返回一个选中的对象列表,每个对象包括一个实例及实例对应的目标主机及候选列表。内部逻辑为:

先对上下文进行升权;

elevated = context.elevated()

用升权后的上下文取获取主机状态;

        hosts = self._get_all_host_states(elevated, spec_obj,
            provider_summaries)

统计instance_uuid(要安置或移动的实例)个数;

        num_instances = (len(instance_uuids) if instance_uuids
                         else spec_obj.num_instances)

如果参数中return_alternates为True,则从CONF中获取最大尝试次数-1存入num_alts,否则该参数设为0。该参数用于指定获取候选host列表的长度。

        num_alts = (CONF.scheduler.max_attempts - 1
                    if return_alternates else 0)

如果instance_uuid为空或USES_ALLOCATION_CANDIDATES为False或alloc_reqs_by_rp_uuid为空,说明使用了一个旧的conductor,因此调用_legacy_find_hosts返回不含候选列表的对象,函数退出。此举为了向前兼容。

        if (instance_uuids is None or
                not self.USES_ALLOCATION_CANDIDATES or
                alloc_reqs_by_rp_uuid is None):
            return self._legacy_find_hosts(context, num_instances, spec_obj,
                                           hosts, num_alts,
                                           instance_uuids=instance_uuids)

在instance_uuid不为空情况下,我们用claimed_instance_uuids数组存放成功通过placement API开辟出资源的实例;用claimed_hosts数组存放被选中的主机。

对于instance_uuids中的每一个实例,返回一个根据权重排好序的满足调度限制的HostState对象列表。如果某一个instance找不到响应的host,则跳出循环。如果顺利,对于与本循环轮次中处理的instance对应的host,如果某个host不匹配资源分配请求,则跳过该host;否则,以alloc_reqs_by_rp_uuid[host_uuid] [0]为参数,借助utils.claim_resources分配资源,当出现成功分配的host时,将该host存入claimed_host数组中,并跳出尝试。如果对于某个claimed_host是空的,说明没有一个host能分配资源给这个实例,分配失败,也不再尝试为其它instance分配资源;如果顺利,则将本instance追加进入已被分配资源的instance列表(claimed_instance_uuids)中,并将为本instance分配资源的host追加进入分配资源的主机列表(claimed_hosts)。然后改变本轮中被选中的主机的资源信息(必然是本instance将消耗一部分资源),以备下一轮筛选使用。

然后,检查一下我们是否为所有请求的instance分配了资源(如果未完全完成请求,则报NoValidHost错误)。

最后,获取候选主机列表,并返回该列表。(那之前分配的主机对应关系去哪了?我认为应该是存入全局信息,因此无需返回)

		for num, instance_uuid in enumerate(instance_uuids):           
        	spec_obj.obj_reset_changes(['instance_uuid'])
            hosts = self._get_sorted_hosts(spec_obj, hosts, num)
            if not hosts:
                break
            claimed_host = None
            for host in hosts:
                cn_uuid = host.uuid
                if cn_uuid not in alloc_reqs_by_rp_uuid:
                    msg = ("A host state with uuid = '%s' that did not have a "
                           "matching allocation_request was encountered while "
                           "scheduling. This host was skipped.")
                    LOG.debug(msg, cn_uuid)
                    continue

                alloc_reqs = alloc_reqs_by_rp_uuid[cn_uuid]
                alloc_req = alloc_reqs[0]
                if utils.claim_resources(elevated, self.placement_client,
                        spec_obj, instance_uuid, alloc_req,
                        allocation_request_version=allocation_request_version):
                    claimed_host = host
                    break

            if claimed_host is None:
                LOG.debug("Unable to successfully claim against any host.")
                break

            claimed_instance_uuids.append(instance_uuid)
            claimed_hosts.append(claimed_host)
           self._consume_selected_host(claimed_host, spec_obj,
                                        instance_uuid=instance_uuid)
			self._ensure_sufficient_hosts(context, claimed_hosts, num_instances,
                claimed_instance_uuids)
        	selections_to_return = self._get_alternate_hosts(
            claimed_hosts, spec_obj, hosts, num, num_alts,
            alloc_reqs_by_rp_uuid, allocation_request_version)
        return selections_to_return

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值