nova scheduler调度器

本文详细解析了OpenStack Nova组件中的实例调度流程,包括从conductor到调度器的具体步骤,如select_destinations方法的调用过程及不同调度器的实现方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

当在conductor中通过_schedule_instances 来调用select_destinations
 def _schedule_instances(self, context, request_spec, filter_properties):
        scheduler_utils.setup_instance_group(context, request_spec,
                                             filter_properties)
        # TODO(sbauza): Hydrate here the object until we modify the
        # scheduler.utils methods to directly use the RequestSpec object
        spec_obj = objects.RequestSpec.from_primitives(
            context, request_spec, filter_properties)
        hosts = self.scheduler_client.select_destinations(context, spec_obj)
        return hosts
从computerTaskmanager中__init__ 中的赋值
from nova.scheduler import client as scheduler_client
self.scheduler_client = scheduler_client.SchedulerClient()
可以看出调用select_destinations 是会调用到scheduler/query.py 中的
from nova.scheduler import rpcapi as scheduler_rpcapi


class SchedulerQueryClient(object):
    """Client class for querying to the scheduler."""

    def __init__(self):
        self.scheduler_rpcapi = scheduler_rpcapi.SchedulerAPI()

    def select_destinations(self, context, spec_obj):
        """Returns destinations(s) best suited for this request_spec and
        filter_properties.

        The result should be a list of dicts with 'host', 'nodename' and
        'limits' as keys.
        """
        return self.scheduler_rpcapi.select_destinations(context, spec_obj)
可以看出scheduler_rpcapi 就是nova.scheduler.rpcapi.py
从SchedulerAPI中的
    def select_destinations(self, ctxt, spec_obj):
        version = '4.3'
        msg_args = {'spec_obj': spec_obj}
        if not self.client.can_send_version(version):
            del msg_args['spec_obj']
            msg_args['request_spec'] = spec_obj.to_legacy_request_spec_dict()
            msg_args['filter_properties'
                     ] = spec_obj.to_legacy_filter_properties_dict()
            version = '4.0'
        cctxt = self.client.prepare(version=version)
        return cctxt.call(ctxt, 'select_destinations', **msg_args)
可以看出这里通过cctxt.call 来进行rpc远程调用,cctxt.call表示会阻塞进程,等待执行结果的返回.这里远程调用到scheduler/manager.py
    def select_destinations(self, ctxt,
                            request_spec=None, filter_properties=None,
                            spec_obj=_sentinel):
        """Returns destinations(s) best suited for this RequestSpec.

        The result should be a list of dicts with 'host', 'nodename' and
        'limits' as keys.
        """

        # TODO(sbauza): Change the method signature to only accept a spec_obj
        # argument once API v5 is provided.
        if spec_obj is self._sentinel:
            spec_obj = objects.RequestSpec.from_primitives(ctxt,
                                                           request_spec,
                                                           filter_properties)
        dests = self.driver.select_destinations(ctxt, spec_obj)
        return jsonutils.to_primitive(dests)

这里会调用driver.select_destinations,这里的driver 会从nova.conf文件中读取
    def __init__(self, scheduler_driver=None, *args, **kwargs):
        if not scheduler_driver:
            scheduler_driver = CONF.scheduler_driver
        try:
            self.driver = driver.DriverManager(
                    "nova.scheduler.driver",
                    scheduler_driver,
                    invoke_on_load=True).driver
在nova.conf 中一般赋值如下:
scheduler_driver = nova.scheduler.filter_scheduler.FilterScheduler
这里的调度器主要有三个实现分别是filter_scheduler.py/chance.py/caching_scheduler.py。从nova.conf中给
scheduler_driver 赋值来看,这三个调度器不能共存,必须选择一个,这里默认用的是FilterScheduler
其中FilterScheduler(driver.Scheduler),也就是说driver.Scheduler是FilterScheduler的父类
而driver.Scheduler 实现如下:
class Scheduler(object):
    """The base class that all Scheduler classes should inherit from."""

    def __init__(self):
        self.host_manager = driver.DriverManager(
                "nova.scheduler.host_manager",
                CONF.scheduler_host_manager,
                invoke_on_load=True).driver
        self.servicegroup_api = servicegroup.API()

    def run_periodic_tasks(self, context):
        """Manager calls this so drivers can perform periodic tasks."""
        pass

    def hosts_up(self, context, topic):
        """Return the list of hosts that have a running service for topic."""

        services = objects.ServiceList.get_by_topic(context, topic)
        return [service.host
                for service in services
                if self.servicegroup_api.service_is_up(service)]

    @abc.abstractmethod
    def select_destinations(self, context, spec_obj):
        """Must override select_destinations method.

        :return: A list of dicts with 'host', 'nodename' and 'limits' as keys
            that satisfies the request_spec and filter_properties.
        """
        return []
可见实现了run_periodic_tasks/hosts_up/select_destinations 这三个接口.子类只要实现这三个接口中的至少一个就行,这里最重要的是select_destinations,也就是要自己写调度器的话,必须实现这个接口.
其中CachingScheduler(filter_scheduler.FilterScheduler):的实现比较简单,仅仅是调用FilterScheduler的
select_destinations

我们这里以chance.py 为例
 def _schedule(self, context, topic, spec_obj):
        """Picks a host that is up at random."""

        elevated = context.elevated()
        hosts = self.hosts_up(elevated, topic)
        if not hosts:
            msg = _("Is the appropriate service running?")
            raise exception.NoValidHost(reason=msg)

        hosts = self._filter_hosts(hosts, spec_obj)
        if not hosts:
            msg = _("Could not find another compute")
            raise exception.NoValidHost(reason=msg)

        return random.choice(hosts)
    def select_destinations(self, context, spec_obj):
        """Selects random destinations."""
        num_instances = spec_obj.num_instances
        # NOTE(timello): Returns a list of dicts with 'host', 'nodename' and
        # 'limits' as keys for compatibility with filter_scheduler.
        dests = []
        for i in range(num_instances):
            host = self._schedule(context, CONF.compute_topic, spec_obj)
            host_state = dict(host=host, nodename=None, limits=None)
            dests.append(host_state)

        if len(dests) < num_instances:
            reason = _('There are not enough hosts available.')
            raise exception.NoValidHost(reason=reason)
        return dests

在select_destinations 通过调用_schedule 来在符合条件的host中随机选择一个host。最终要的一条语句就是
random.choice(hosts),这也是chance.py 这个调度器命名的原因.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值