OpenStack源码探秘(一)——Nova-Scheduler

OpenStack源码探秘(一)——Nova-Scheduler

OpenStack源码探秘(二)——Oslo.Config


许久没有更新OpenStack源码探秘系列了。最近换工作颇不顺利,许多笔者心仪的公司都因为这样或那样的原因而失之交臂,这样下去可能会考虑到互联网公司做些服务器端的工作。晚上回到家心情都不太好,懒得动笔,不过经过了几天起伏,心态也慢慢调整过来了,今天就给大家分享一篇Nova-Scheduler的源码架构分析。


        Nova的代码相比Glance来说要复杂许多,整体的架构类似于Twisted的异步回调消息架构,通过AMPQ框架(RabbitMQ)实现了服务间的消息传递机制。关于Nova的整体架构的文章CSDN上有许多,大家可以看看做引申阅读,不过可能需要掌握些基础知识才能读懂。这里先暂时搁置,今后规划好可能会给大家进行些心得的分享。

        选择Nova-Scheduler这个服务作为OpenStack源码探秘系列的开头,是因为Nova-Scheduler的架构是比较简单易懂的,万事开头难,适合开篇。然后Nova-Scheduler在OpenStack中的作用却是非常重要的,负责虚拟机的调度,决定虚拟机或volume磁盘运行在哪台物理服务器上。Nova-Scheduler看似简单,是因为其实现了非常好的架构,方便我们开发者根据公司的业务或产品特点,自行增添开发适合我们的调度算法。

        我们先大体分析Nova-Scheduler的整体结构:

        看一下Nova-Scheduler的服务管理入口,Manage.py(OpenStack所有服务的入口都是以这个名字命名的),看看虚机调度实现了那些功能

class SchedulerManager(manager.Manager):
    """Chooses a host to run instances on."""

    RPC_API_VERSION = '2.6'

    def __init__(self, scheduler_driver=None, *args, **kwargs):
        ......

    def update_service_capabilities(self, context, service_name,
                                    host, capabilities):
        """Process a capability update from a service node."""
        if not isinstance(capabilities, list):
        ......

    def create_volume(self, context, volume_id, snapshot_id,
                      reservations=None, image_id=None):
        #function removed in RPC API 2.3
        pass

    def live_migration(self, context, instance, dest,
                       block_migration, disk_over_commit):
        ......

    def run_instance(self, context, request_spec, admin_password,
            injected_files, requested_networks, is_first_time,
            filter_properties):
        """Tries to call schedule_run_instance on the driver.
        Sets instance vm_state to ERROR on exceptions
        """
        ......

    def prep_resize(self, context, image, request_spec, filter_properties,
                    instance, instance_type, reservations):
        """Tries to call schedule_prep_resize on the driver.
        Sets instance vm_state to ACTIVE on NoHostFound
        Sets vm_state to ERROR on other exceptions
        """
	......

    def show_host_resources(self, context, host):
        """Shows the physical/usage resource given by hosts.

        :param context: security context
        :param host: hostname
        :returns:
            example format is below::

                {'resource':D, 'usage':{proj_id1:D, proj_id2:D}}
                D: {'vcpus': 3, 'memory_mb': 2048, 'local_gb': 2048,
                    'vcpus_used': 12, 'memory_mb_used': 10240,
                    'local_gb_used': 64}

        """
        # Getting compute node info and related instances info
        ......

    def select_hosts(self, context, request_spec, filter_properties):
        """Returns host(s) best suited for this request_spec and
        filter_properties"""
        ......

        只是对部分代码进行了节选,我们看到SchedulerManger提供的服务包括run_instance(启动虚拟机)、live_migration(虚拟机动态迁移)、prep_resize(虚拟机资源再分配)这几个服务都需要决定虚拟机调度到哪个物理节点。

        决策一个虚机应该调度到某物理节点,需要分两个步骤:过滤(Fliter)和计算权值(Weight):

        1、通过过滤(Fliter),我们过滤掉不符合我们的要求,或镜像要求(比如物理节点不支持64bit,物理节点不支持Vmware EXi等)的主机,留下符合过滤算法的主机集合。

OpenStack源码探秘(一)——Nova-Scheduler_第1张图片

        2、第二步进行虚机消耗权值的计算。通过指定的权值计算算法,计算在某物理节点上申请这个虚机所必须的消耗cost,物理节点越不适合这个虚机,消耗cost就越大,权值Weight就越大,调度算法会选择权值最小的主机。比如说在一台低性能主机上创建一台功能复杂的高级虚拟机的代价是高的。配置文件中默认的算法是主机的剩余内存越大,权值越低,就越容易被选上。

OpenStack源码探秘(一)——Nova-Scheduler_第2张图片

        OpenStack默认支多种过滤策略,如CoreFilter(CPU数过滤策略)、RamFilter(Ram值选择策略)、AvailabilityZoneFilter(指定集群内主机策略)、JsonFiliter(JSON串指定规则策略)。开发者也可以实现自己的过滤策略。在nova.scheduler.filters包中的过滤器有以下几种:

OpenStack源码探秘(一)——Nova-Scheduler_第3张图片

        下面我们来看一下Filter的UML图:

OpenStack源码探秘(一)——Nova-Scheduler_第4张图片

Filter相关类图

        一提到策略、算法等等的字眼,我们在设计模式中自然就会想到Strategy模式(策略模式)。策略模式定义了一系列的算法,并将每一个算法封装起来,而且使它们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化。

OpenStack源码探秘(一)——Nova-Scheduler_第5张图片

        Filter过滤和cost_weight权值计算确实是应用了这样的场景,统一各个算法的接口,通过HostFilterHandler(Context)类,动态的选择单一算法或算法组合。每个Filter子类都分别实现了host_passes接口,它们使用各自的算法,将传入参数的host_state主机进行过滤,返回boolen,判断这个传入的物理节点是否符合过滤要求。HostFilterHandler类通过继承基类BaseFilterHandler的get_filtered_objects方法,使用ConcreteFilter的算法,并在运行时刻动态动态设置应用哪个或那几个算法。

        另外Filter算法在nova-scheduler中是通过oslo.config.cfg模块从nova.conf配置文件中动态读取的,应用了Python的反射机制,在运行时刻决定初始化某些filter算法子类,在不需要重新编译和修改代码的前提下,便捷的替换功能。

def get_filtered_objects(self, filter_classes, objs,
            filter_properties):
        for filter_cls in filter_classes:
            objs = filter_cls().filter_all(objs, filter_properties)
        return list(objs)
        分析了许多OpenStack的代码,应用设计模式的经典例子确实很多。很晚了,今天先写到这里,后面有时间会分享OpenStack其他模块的代码,欢迎关注、讨论。

你可能感兴趣的:(算法,filter,源代码,openstack)