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 两种实现方式。

二、主要源码说明

1 、 manager.py :

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

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

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

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

2 、 driver.py 、 chance.py 、 filter_scheduler.py 、 caching_scheduler.py :

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

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

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

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

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

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

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

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

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

4 、 filters :

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

1 ) __init__.py :

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

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

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

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

5 、 weights :

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

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

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

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

三、流程与算法说明

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

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

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

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

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

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

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

7 )然后根据配置指定的 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

8 )在 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)

9 )从 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 )步骤。

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

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

host_weight = Weigher1_multiplier * Weigher1_host_weight+……+ WeigherN_multiplier

* WeigherN_host_weight

举例说明:

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

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

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

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

1 )假若 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

2 )假若 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

3 )假若 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

4 )最后得出 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

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

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

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

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

3 ) 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

nova分析(7)—— nova-scheduler,布布扣,bubuko.com

时间: 2024-10-10 05:03:22

nova分析(7)—— nova-scheduler的相关文章

nova分析(3)—— nova-api

nova-api是nova对外提供Restful API的服务,Horizon.novaclient等均通过该api与nova进行通信. nova其实对外提供了多个api服务,包括下面这些服务: nova-apinova-api-ec2nova-api-metadatanova-api-os-compute 其中,nova-api用于启动其他三个服务.下面逐个分析下. nova-api 入口在 nova.cmd.api:main ,主要是基于WSGI.PasteDeploy.Webob.Rout

Nova分析(1)——整体架构

Conceptual Diagram Logical diagram Nova is the most complicated and distributed component of OpenStack. A large number of processes cooperate to turn end user API requests into running virtual machines. Below is a list of these processes and their fu

Openstack之Nova分析

前言  Openstack作为一个虚拟机管理平台,核心功能自然是虚拟机的生命周期的管理,而负责虚机管理的模块就是 Nova. 本文就是openstack中Nova模块的分析,所以本文重点是以下三点: 先了解Openstack的整体架构,搞清楚为什么要用这样的架构: 然后再了解架构中的各个组件,组件提供的主要功能与各个组件之间的交互: 了解虚机的启动过程,能在遇到问题时发现问题出在哪个模块中的哪个组件. Nova组件介绍 接下来进行详细介绍,如有错误,欢迎拍砖! 下图为创建虚拟机的一个大概流程图.

nova分析(4)—— nova-cells

cells的功能允许用户以更分散的方式去扩展OpenStack计算云而无需使用复杂的技术,比如数据库和消息队列的集群.它的目的是支持非常大规模的部署. 当启用了此功能,在OpenStack计算云中的主机被划分为组称为cells.cells可以被配置成树形结构.顶层的cell的主机应该运行nova-api服务,但是没有nova-compute服务.每一个childcell在常规的计算云中应该运行除了nova-api之外的所有nova-*类型的服务.可以认为,作为正常的计算部署的cells,每一个c

nova分析(2)—— nova-all

nova-all是一个用来启动所有nova服务的辅助脚本,注意只是启动所有服务,不包括停止和重启等功能. nova-all的入口在 nova.cmd.all:main ,脚本也比较简单,这儿就贴下代码了 def main(): # 命令行参数解析,实际上命令行参数并没有使用 config.parse_args(sys.argv) logging.setup("nova") LOG = logging.getLogger('nova.all') utils.monkey_patch()

nova分析(5)—— nova-conductor

nova-conductor是nova-compute之上的一个服务,这个服务比较简单,主要封装了DB访问和动态迁移相关的代码.转来一篇文章看看它是如何工作的. 更新记录:1. 2013.4.19  增加对nova-conductor的优势和劣势分析 正文:在Grizzly版的Nova中,取消了nova-compute的直接数据库访问.大概两个原因:1. 安全考虑.Benefit:因为compute节点通常会运行不可信的用户负载,一旦服务被攻击或用户虚拟机的流量溢出,则数据库会面临直接暴露的风险

nova分析(9)—— nova-novncproxy

nova提供了novncproxy代理支持用户通过vnc来访问虚拟机,用户可以通过websocket.java客户端或者spicehtml5来访问.通过websket访问虚拟机的功能已经集成到horizon中,而通过java客户端则需要先安装相应的软件.为了方便用户访问虚拟机,nova通过有一个proxy来实现,proxy通常同nova-api一起部署. vnc访问的实现方法如下,首先是启动一个虚拟机时启用vnc,这可以通过给kvm加上vnc参数即可.这样,kvm就会启动一个vncserver监

nova分析(10)—— nova-rootwrap

一.nova-rootwrap的作用 部署玩过openstack的都应该知道,它会生成一个nova用户来管理所有服务.nova身份在linux中属于普通用户级别,避免了一些需要root身份运行的操作,提高linux系统的安全性.但是openstack在实际过程中会调用很多外部命令,例如就network服务而言就有:`ip`,`ovs-vsctl`,`iptables`,`dnsmasq`,`brctl`等等,这些命令在linux中都是需要以root身份来运行的,如果是普通用户通常的做法是在命令前

KVM 介绍(8):使用 libvirt 迁移 QEMU/KVM 虚机和 Nova 虚机 [Nova Libvirt QEMU/KVM Live Migration]

学习 KVM 的系列文章: (1)介绍和安装 (2)CPU 和 内存虚拟化 (3)I/O QEMU 全虚拟化和准虚拟化(Para-virtulizaiton) (4)I/O PCI/PCIe设备直接分配和 SR-IOV (5)libvirt 介绍 (6)Nova 通过 libvirt 管理 QEMU/KVM 虚机 (7)快照 (snapshot) (8)迁移 (migration) 1. QEMU/KVM 迁移的概念 迁移(migration)包括系统整体的迁移和某个工作负载的迁移.系统整理迁移