zoukankan      html  css  js  c++  java
  • nova分析(7)—— nova-scheduler

    Nova-Scheduler主要完成虚拟机实例的调度分配任务,创建虚拟机时,虚拟机该调度到哪台物理机上,迁移时若没有指定主机,也需要经过scheduler。资源调度是云平台中的一个很关键问题,如何做到资源的有效分配,如何满足不同情况的分配方式,这些都需要nova-scheduler来掌控,并且能够很方便的扩展更多的调度方法,可能我需要虚拟机调度到空闲的机器,可能还需要将某类型的虚拟机调度到固定的机架等等,现在就来看看Nova-Scheduler是如何完成调度任务的。

    Scheduler启动后,相应的MQ结构如下:

    Exchange(nova,topic) <--- <routing_key:scheduler>---Queue(scheduler) ---> Consumer(scheduler)
    
    Exchange(nova,topic) <---<routing_key:scheduler.controller>---Queue(scheduler.controller) ---> Consumer(scheduler.controller)
    
    Exchange(scheduler_fanout,fanout) <---<routing_key:scheduler>---Queue(scheduler_fanout_xxx)--->Consumer(scheduler_fanout_xxx)

    一、服务启动

    Nova-scheduler 服务的启动入口脚本是 cmd 包下的 scheduler.py ,其主要监听来自于消息队列中 topic=scheduler( 可配置 ) 的消息。在服务启动过程中,其将初始化一个 SchedulerManager 实例作为该服务的 Handler ,来处理接受到的消息请求。

    同时, Nova-scheduler 服务在启动的过程中,会将自己注册到 DB 中,即将自己的 host 、 binary 、 topic 、 report_count 信息添加到 services 表中,并将自己同样注册到 ServiceGroup 服务中,默认是 DBServiceGroup 服务,并定时向ServiceGroup 服务发送心跳,其本质上就是定时地更新 services 表中的report_count 字段。另, ServiceGroup 服务还有基于 MC 、 ZK 两种实现方式。

    二、主要源码说明

    、 manager.py 

    SchedulerManager 类主要来处理服务接收的消息,目前主要的操作就是live_migration 

    run_instance 、 prep_resize 、 select_hosts 、 select_destinations ,后两者将要 deprecated 。这些操作本质上还是要依赖于具体的 SchedulerDriver 去完成。

    另外, _SchedulerManagerV3Proxy 类与 SchedulerManager 类主要的区别在于消息版本的不同,

    _SchedulerManagerV3Proxy 消息是 3.0 版本,而 SchedulerManager 是 2.9 版本。

    、 driver.py 、 chance.py 、 filter_scheduler.py 、 caching_scheduler.py 

    Scheduler 类是所有 SchedulerDriver 类的基类,其定义了关键的接口协议。目前主要有 ChanceScheduler 、 FilterScheduler 和 CachingScheduler 三种实现方式,具体说明如下:

    ) ChanceScheduler :随机选择一台物理机,前提是该物理机上的 nova-compute 服务正常且该物理机不在指定的 ignore_hosts 列表中。

    ) FilterScheduler :筛选出能通过整个过滤器链的物理机,然后根据相应指标计算权重,并进行排序,最后返回一个 best host 。具体过滤器详见下文。

    ) CachingScheduler : FilterScheduler 的子类,在 FilterScheduler 的基础上将 host 资源信息缓存在了本地内存中,然后通过后台定时任务定时从 DB 中拉取最新的 host 资源信息。在多节点环境下存在问题。

    、 host_manager.py HostState :表示物理机的资源信息集合,比如当前可用内存、已用内存、虚拟机数量、任务数量、 io 负载、可用磁盘、已用磁盘等等,以及一些更新方法。

    HostManager :该类是最重要的 host 筛选类,其内部主要有三个关键函数:

    get_filtered_hosts :返回经过层层过滤器筛选后的 host 列表,其依赖于FilterHandler

    get_weighed_hosts :返回经过权重计算排序后的 host 列表,其依赖于WeightHandler

    get_all_host_states :获取当前最新的 host 资源列表。

    、 filters 

    这里是全部的各种 filter 的实现方式,主要有:

    ) __init__.py 

    BaseHostFilter :继承自 BaseFilter ,是所有具体 Filter 子类的基类,其中一个较重要的成员变量 run_filter_once_per_request 表示该 Filter 子类是否在在一次 request 中仅执行一次。

    HostFilterHandler :最重要的函数 get_filtered_objects , load 指定的filter_classes ,层层过滤

    host ,最后返回符合所有过滤条件的 host 列表。

    )剩余就是很多个不同的具体 Filter 子类的实现,基于各自不同的策略,具体暂不一一介绍。

    、 weights 

    ) __init__.py BaseHostWeigher :继承自 BaseWeigher ,是所有具体 Weigher 子类的基类,其中主要的函数就是 _weigh_object ,由具体子类实现,完成对目标 host 列表权重的计算与排序,具体策略见下文。

    HostWeightHandler :最重要的函数 get_weighed_objects , load 指定的weigher_classes ,层层依据各自指标对目标 host 列表进行权重计算,最后排序后返回。

    ) ram.py RAMWeigher :基于剩余可用内存进行权重计算排序。

    ) metrics.py MetricsWeigher :支持自定义一些指标进行权重计算排序。

    三、流程与算法说明

    、这里主要是基于 FilterScheduler 来说明下在 Scheduler 服务中创建虚拟机(包括筛选物理机)的流程(其他流程同理):

    )当 nova-scheduler 服务从 MQ 中接收到 run_instance 消息时,则由SchedulerManager 类对其进行处理,执行 run_instance 函数。

    ) SchedulerManager 将具体逻辑交由具体的 SchedulerDriver 执行,这里就是 FilterScheduler 

    ) FilterScheduler 接收到请求后,开始进行 host 筛选,选择出 instance_num个目标 host 

    )首先判断这次 request 的 retry 次数是否已经达到 max_attempts 次,若达到,则停止 retry ,抛出 NoValidHost 异常;若是第一次,则设置 filter_properties 属性 retry={num_attempts:1,hosts:[]} ;否则继续执行。

    )然后从 DB 中获取当前最新的 compute node 节点资源信息,并更新本地内存 缓存 中的 host 表资源数据。这里的好处是当一次批量申请多个虚拟机时,可以避免多次请求DB ,但是一个不容忽视的问题就是如果多个 Scheduler 服务并行部署时,就会因资源信息的延迟不同步而导致虚拟机创建失败(实际后台 host 已不足)。

    )再次开始循环为每个 instance 筛选目标 host :首先根据指定的ignore_hosts 、 force_hosts force_nodes 属性对候选 hosts 列表进行筛选,留下符合这些属性条件的 hosts

    )然后根据配置指定的 filter 来循环层层过滤 6 )中的候选 hosts ,具体代码如下:

    def get_filtered_objects(self, filter_classes, objs,filter_properties, index=0):
            list_objs = list(objs)
            LOG.debug(_("Starting with %d host(s)"), len(list_objs))
            for filter_cls in filter_classes:
            cls_name = filter_cls.__name__
            filter = filter_cls()
    
             if filter.run_filter_for_index(index):
               objs = filter.filter_all(list_objs,filter_properties)
               if objs is None:
                   LOG.debug(_("Filter %(cls_name)s says to stop filtering"),
                       {'cls_name': cls_name})
                return
              list_objs = list(objs)
              if not list_objs:
                LOG.info(_("Filter %s returned 0 hosts"), cls_name)
                break
              LOG.debug(_("Filter %(cls_name)s returned  %(obj_len)d host(s)"),
                 {'cls_name': cls_name, 'obj_len': len(list_objs)})
            return list_objs

    )在 7 )中筛选的这批 hosts 此时可以认为是满足该 instance 的资源要求,然后开始对这批hosts 根据配置的各个 Weigher 子类进行权重计算并排序,具体如下:

    def get_weighed_objects(self, weigher_classes, obj_list,weighing_properties):
       """Return a sorted (descending), normalized list of WeighedObjects."""
    
      if not obj_list:
           return []
    
      weighed_objs = [self.object_class(obj, 0.0) for obj in obj_list]
      for weigher_cls in weigher_classes:
            weigher = weigher_cls()
            weights = weigher.weigh_objects(weighed_objs, weighing_properties)
    
            # Normalize the weights
            weights = normalize(weights,minval=weigher.minval,maxval=weigher.maxval)
    
             for i, weight in enumerate(weights):
                  obj = weighed_objs[i]
                  obj.weight += weigher.weight_multiplier() * weight
    
               return sorted(weighed_objs, key=lambda x: x.weight, reverse=True)

    )从 8 )中根据权重排序后的 hosts 取出 scheduler_host_subset_size (默认是 1 )个 host ,表明未来该 instance 会落在该 host 上,并 预扣掉该 host 的剩余可用资源 (注意这里仅仅是修改的本地缓存中 host 资源信息)。

    10 )在为每个 instance 选择好候选目标 host 后,开始循环创建虚拟机:更新instance ( host,node,scheduled_at ),并向 nova-compute 服务发送 rpc 请求。

    11 ) nova-compute 服务接收到创建虚拟机请求后:首先将 DB 中 instance状态设置为vm_state=BUILDING , task_state=SCHEDULING 

    12 )然后获取该 node 的 ResourceTracker 实例(其主要是维护跟踪该 node 的资源明细),claim 将要预留资源信息,设置 mac 和 network 信息,最后开始构建虚拟机。期间在不同的 task 阶段,会相应更新 DB 中 vm_state 和 task_state 状态。

    13 )若创建虚拟机流程中发生错误,会重新向 MQ 发送创建虚拟机请求,此时nova-scheduler服务会继续处理该消息,则继续回到 1 )步骤。

    、下图展示了整个调度过程的大体流程:

    这里主要说明下各个 host 的权重是如何计算出来的,大体公式如下: 

    host_weight = Weigher1_multiplier * Weigher1_host_weight+……+ WeigherN_multiplier

    * WeigherN_host_weight

    举例说明:

    假若有 6 台候选 Host : H1 , H2 , H3 , H4 , H5 , H6

    个 Weigher : W1 , W2 , W3 ,且其 multiplier 分别为 1 , 2 , 1

    具体一个 Weigher 如何计算出一个 Host 在该 Weigher 的权重,则依赖各个Weigher 自己的

    实现,比如 RAMWeigher 则是以每个 Host  free_ram_mb 作为其原生权重。

    )假若 H1~H6 经过 W1 计算后的原生权重值如下:

    W(multiplier)

    H1

    H2

    H3

    H4

    H5

    H6

    W1 (1)

    50

    10

    20

    10

    90

    110

    然后需要对这些原始权重值进行 normalize 化,具体方式是:找出这些原始权重值中的

    最大值 max_weight 和最小值 min_weight ,然后按照如下公式来计算其比例权重值:

    ratio_weight = ( raw_weight - min_weight ) / ( max_weight - min_weight )

    那么 H1~H6 原生权重 W1 normalize 化之后 (ratio_weight) 

    W(multiplier)

    H1

    H2

    H3

    H4

    H5

    H6

    W1 (1)

    0.4

    0

    0.1

    0

    0.8

    1

    )假若 H1~H6 经过 W2 计算后的原生权重值如下:

    W(multiplier)

    H1

    H2

    H3

    H4

    H5

    H6

    W1 (1)

    0.4

    0

    0.1

    0

    0.8

    1

    W2 (2)

    10

    4

    6

    11

    1

    9

    那么 H1~H6 原生权重 W2 normalize 化之后 (ratio_weight) 

    W(multiplier)

    H1

    H2

    H3

    H4

    H5

    H6

    W1 (1)

    0.4

    0

    0.1

    0

    0.8

    1

    W2 (2)

    0.9

    0.3

    0.5

    1

    0

    0.8

    )假若 H1~H6 经过 W3 计算后的原生权重值如下:

    W(multiplier)

    H1

    H2

    H3

    H4

    H5

    H6

    W1 (1)

    0.4

    0

    0.1

    0

    0.8

    1

    W2 (2)

    0.9

    0.3

    0.5

    1

    0

    0.8

    W3 (1)

    15

    25

    10

    5

    10

    5

    那么 H1~H6 原生权重 W3 normalize 化之后 (ratio_weight) 

    W(multiplier)

    H1

    H2

    H3

    H4

    H5

    H6

    W1 (1)

    0.4

    0

    0.1

    0

    0.8

    1

    W2 (2)

    0.9

    0.3

    0.5

    1

    0

    0.8

    W3 (1)

    0.5

    1

    0.25

    0

    0.25

    0

    )最后得出 H1~H6 的最终权重为:

    W(multiplier)

    H1

    H2

    H3

    H4

    H5

    H6

    W1 (1)

    0.4

    0

    0.1

    0

    0.8

    1

    W2 (2)

    0.9

    0.3

    0.5

    1

    0

    0.8

    W3 (1)

    0.5

    1

    0.25

    0

    0.25

    0

    ratio_weights

    2.7

    1.6

    1.35

    2

    1.05

    2.6

    )最后对 H1~H6 的 ratio_weight 进行降序排序,那么这次 Host 的排序则为H1 , H6 , H4 , H2 , H3 , H5

    、 nova-scheduler 与 nova-compute 之间是如何知道具体 host 资源的详情的?

    )每当 nova-compute 服务起来之后,会自动更新 DB 中对应 compute_node的资源信息,若是第一次,则会将自己添加到 compute_node 中;并同时会将这些资源信息缓存在本地内存中,并由一个 ResourceTracker 实例进行跟踪。

    )每次 nova-compute 服务接收到创建虚拟机的申请时,通过ResourceTracker 进行instance_claim 时,会将这次申请所需要扣除的虚拟机资源大小及时反映到compute node 中,同时更新本地 ResourceTracker 中的缓存信息。

    ) nova-scheduler 每次在接收到创建虚拟机请求时,都会从 compute node中取出最新的 host 源信息,被暂时缓存在本地内存中,当成功选择出一台 host 时,会及时扣除本地缓存相应的 host 资源信息。

    参考文档

    http://www.choudan.net/2013/08/11/Nova-Scheduler分析.html

    http://www.choudan.net/2013/08/09/Nova-Service启动.html

    http://blog.csdn.net/gaoxingnengjisuan/article/details/15615743

    http://blog.csdn.net/cloudresearch/article/details/19051043

    http://blog.csdn.net/gaoxingnengjisuan/article/details/15734437

    http://www.tuicool.com/articles/Vn2iia

    http://docs.openstack.org/developer/nova/devref/filter_scheduler.html

  • 相关阅读:
    linux下启动和关闭网卡命令及DHCP上网
    python 编码问题
    paddlepaddle
    Convolutional Neural Network Architectures for Matching Natural Language Sentences
    deep learning RNN
    Learning Structured Representation for Text Classification via Reinforcement Learning 学习笔记
    Python IO密集型任务、计算密集型任务,以及多线程、多进程
    EM 算法最好的解释
    tensorflow 调参过程
    tensorflow 学习纪录(持续更新)
  • 原文地址:https://www.cnblogs.com/feisky/p/3875361.html
Copyright © 2011-2022 走看看