深挖Openstack Nova - Scheduler调度策略

 

一.  Scheduler的作用就是在创建实例(instance)时,为实例选择出合适的主机(host)。这个过程分两步:过滤(Fliter)和计算权值(Weight)

1. 过滤:

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

2. 计算权值

通过指定的权值计算算法,计算在某物理节点上申请这个虚机所必须的消耗cost。物理节点越不适合这个虚机,消耗cost就越大,权值Weight就越大,调度算法会选择权值最小的主机。

二. 过滤策略

Filter算法在nova-scheduler中是通过oslo.config.cfg模块从nova.conf配置文件中动态获取的,应用了Python的反射机制,在运行时刻决定初始化所选择的filter算法。

OpenStack支持多种过滤策略,均在/nova/scheduler/filters包下:

1. CoreFilter:根据CPU数过滤主机

2. RamFilter:根据指定的RAM值选择资源足够的主机

3. AvailabilityZoneFilter:返回创建虚拟机参数指定的集群内的主机

4. JsonFilter:根据JSON串指定的规则选择主机

三. 目录结构

1. /nova/scheduler/filter_scheduler.py:继承于类Scheduler,实现基于主机过滤器选取主机节点方式的调度器

2. /nova/scheduler/host_manager.py: 描述了跟调度器操作相关的主机的实现,其中,HostState类描述了从主机获取相关数据和状态的一些实现,HostManager类描述了跟调度器操作相关的一些主机管理实现

3. /nova/weights.py:实现了跟计算权值相关的方法

四. 分析调度_schedule方法

该方法对应在/nova/scheduler/filter_scheduler.py中

  1.  
    # 调度方法,返回一系列满足要求的主机(host)
  2.  
    def _schedule(self, context, request_spec, filter_properties)

1. 信息初始化

  1.  
    # 返回带有admin标志设置的context的版本
  2.  
    elevated = context.elevated()
  3.  
    # 获取实例信息
  4.  
    instance_properties = request_spec['instance_properties']

2. 更新过滤器属性信息

  1.  
    filter_properties.update({'context': context,
  2.  
    'request_spec': request_spec,
  3.  
                              'config_options': config_options,
  4.  
                             'instance_type': instance_type})

3. 过滤不可用的host

  1.  
    # 过滤掉不可用的主机节点
  2.  
    hosts = self._get_all_host_states(elevated)

深入_get_all_host_states方法,对应的是/nova/scheduler/host_manager.py。

(1)获取可用的计算节点

  1.  
    # 获取可用计算节点的资源使用情况
  2.  
    # 获取所有compute_node(计算节点)
  3.  
    compute_nodes = objects.ComputeNodeList.get_all(context)

(2)设置基本信息

  1.  
    # 获取主机host
  2.  
    host = compute.host
  3.  
    # 获取hypervisor_hostname作为节点名
  4.  
    node = compute.hypervisor_hostname
  5.  
    state_key = (host, node)
  6.  
    # 从host_state_map获取并更新host状态
  7.  
    host_state = self.host_state_map.get(state_key)
  8.  
    if host_state:
  9.  
        host_state.update_from_compute_node(compute)
  10.  
    else:
  11.  
        host_state = self.host_state_cls(host, node, compute=compute)
  12.  
        self.host_state_map[state_key] = host_state

(3)更新host状态

  1.  
    # 每次请求到来都要更新host状态
  2.  
    host_state.aggregates = [self.aggs_by_id[agg_id] for agg_id in
  3.  
                             self.host_aggregates_map[
  4.  
                                host_state.host]]
  5.  
    host_state.update_service(dict(service))
  6.  
    self._add_instance_info(context, compute, host_state)
  7.  
    seen_nodes.add(state_key)

(4)删除不活跃的计算节点

  1.  
    # 从host_state_map中删除不活跃的计算节点
  2.  
    dead_nodes = set(self.host_state_map.keys()) - seen_nodes
  3.  
    for state_key in dead_nodes:
  4.  
        host, node = state_key
  5.  
        LOG.info(_LI("Removing dead compute node %(host)s:%(node)s "
  6.  
                    "from scheduler"), {'host':host, 'node': node})
  7.  
        del self.host_state_map[state_key]

4.循环遍历实例,获取符合过滤要求的host

  1.  
    for num in range(num_instances):
  2.  
        # 基于具体要求过滤本地主机
  3.  
        hosts = self.host_manager.get_filtered_hosts(hosts,
  4.  
                filter_properties, index=num)
  5.  
        # 一个符合要求的host都没有
  6.  
        if not hosts:
  7.  
            break

深入get_filtered_hosts方法,对应的是/nova/scheduler/host_manager.py。

(1)定义所要使用的过滤器

  1.  
    # 如果没有设置过滤器,则使用默认的过滤器
  2.  
    if filter_class_names is None:
  3.  
        filters = self.default_filters
  4.  
    else:
  5.  
        # 获取过滤器方法
  6.  
        filters = self._choose_host_filters(filter_class_names)

(2)然后处理三种类型的host

1》忽略的host

ignore_hosts = filter_properties.get('ignore_hosts', [])
  1.  
    # 除去忽略的host
  2.  
    def _strip_ignore_hosts(host_map, hosts_to_ignore):

2》强制使用的host

force_hosts = filter_properties.get('force_hosts', [])
  1.  
    # 匹配强制使用的host
  2.  
    def _match_forced_hosts(host_map, hosts_to_force):

3》强制使用的nodes

force_nodes = filter_properties.get('force_nodes', [])
  1.  
    # 匹配强制使用的nodes
  2.  
    def _match_forced_nodes(host_map, nodes_to_force):

(3)返回满足过滤条件的host对象

  1.  
    # 执行过滤操作,返回满足所有过滤条件的host对象
  2.  
    return self.filter_handler.get_filtered_objects(filters,
  3.  
            hosts, filter_properties, index)

5. 对主机进行称重

  1.  
    # 获取并返回一个WeightedObjects的主机排序列表(最高分排在第一)
  2.  
    weighted_hosts = self.host_manager.get_weighted_hosts(hosts,
  3.  
            filter_properties)

深入get_weighted_hosts方法,最终对应的是/nova/weights.py。

(1)用相乘累加的方式计算host主机的权重

  1.  
    # 根据多方面参数来判定权值,比如主机剩余内存、剩余磁盘空间、vcpu的使用情况
  2.  
    # 每个参数乘于一个weight,累加得到host主机的权值
  3.  
    for i, weight in enumerate(weights):
  4.  
        obj = weighted_objs[i]
  5.  
        obj.weight += weigher.weight_multiplier() * weight

(2)将获取权值的host主机排序后返回

  1.  
    # 对WeighedObjects列表进行排序返回
  2.  
    return sorted(weighed_objs, key=lambda x: x.weight, reverse=True)

开发者也可以实现自己的权值计算函数,对于OpenStack采用的方法来说,主机拥有的剩余内存越多,权值越小,被选择在其上创建虚拟机的可能性就越大。

6. 设置调度使用的主机数目

  1.  
    # scheduler_host_subset_size:定义了新的实例将会被调度到一个主机上
  2.  
    # 这个主机是随机从最好的(分数最高的)N个主机组成的子集中选择出来
  3.  
    scheduler_host_subset_size = CONF.scheduler_host_subset_size
  4.  
    if scheduler_host_subset_size > len(weighed_hosts):
  5.  
        scheduler_host_subset_size = len(weighed_hosts)
  6.  
    if scheduler_host_subset_size < 1:
  7.  
        scheduler_host_subset_size = 1

7. 获取随机选择出来的主机

  1.  
    # 从分数最高的若干主机组成的子集中,随机选择一个主机
  2.  
    # 新的实例将会调度到这个主机上
  3.  
    chosen_host = random.choice(
  4.  
        weighed_hosts[0:scheduler_host_subset_size])
  5.  
    LOG.debug("Selected host: %(host)s", {'host': chosen_host})
  6.  
    # 把选好的主机增加到selected_hosts列表中
  7.  
    selected_hosts.append(chosen_host)

8. 为下一次实例选择主机做好准备

  1.  
    # 此次选择了一个主机后,在下一个实例选择主机前,更新主机资源信息
  2.  
    chosen_host.obj.consume_from_instance(instance_properties)
  3.  
    if update_group_hosts is True:
  4.  
        if isinstance(filter_properties['group_hosts'], list):
  5.  
            filter_properties['group_hosts'] = set(
  6.  
                filter_properties['group_hosts'])
  7.  
        filter_properties['group_hosts'].add(chosen_host.obj.host)

9. 返回所有实例选择的主机列表

  1.  
    # 循环为每一个实例获取合适的主机后,返回选择的主机列表
  2.  
    return selected_hosts

深挖Openstack Nova - Scheduler调度策略的更多相关文章

  1. OpenStack Nova Release(Rocky to Train)

    目录 文章目录 目录 前言 演进方向 Cellv2 更新 Rocky Support disabling a cell Stein Handling a down cell Train Count q ...

  2. OpenStack Nova 高性能虚拟机之 NUMA 架构亲和

    目录 文章目录 目录 写在前面 计算平台体系结构 SMP 对称多处理结构 NUMA 非统一内存访问结构 MPP 大规模并行处理结构 Linux 上的 NUMA 基本对象概念 NUMA 调度策略 获取宿 ...

  3. OpenStack nova VM migration (live and cold) call flow

    OpenStack nova compute supports two flavors of Virtual Machine (VM) migration: Cold migration -- mig ...

  4. OpenStack Nova

    OpenStack Nova 简介 OpenStack 中的 Nova 负责维护和管理云环境的计算资源 Nova 在现有 Linux 服务器上作为一组守护线程来提供服务 Nova 由多个服务器进程组成 ...

  5. OpenStack Nova 高性能虚拟机之 CPU 绑定

    目录 文章目录 目录 前文列表 KVM KVM 的功能列表 KVM 工具集 KVM 虚拟机的本质是什么 vCPU 的调度与性能问题 Nova 支持的 vCPU 绑定 vcpu\_pin\_set 配置 ...

  6. Openstack Nova 源码分析 — Create instances (nova-conductor阶段)

    目录 目录 前言 Instance Flavor Instance Status Virt Driver Resource Tracker nova-conductor Create Instance ...

  7. OpenStack Nova启动实例流程

    1.概述 启动一个新的实例,会涉及到OpenStack Nova中的多个组件: API服务器,接收用户端的请求,并且将其传递给云控制器. 云控制器,处理计算节点.网络控制器.API服务器和调度器之前的 ...

  8. openstack nova 创建虚机流程

    1文件 nova.api.openstack.coumpute.servers1函数 def create(self, req, body):1调用 (instances, resv_id) = se ...

  9. Openstack Nova 添加计算节点(六.一)

    Openstack Nova 添加计算节点(六.一) # 重要的两点: 1 时间同步 2 yum 源 # 安装软件: yum install openstack-selinux openstack-n ...

随机推荐

  1. 系统学习 Java IO (十一)----打印流 PrintStream

    目录:系统学习 Java IO---- 目录,概览 PrintStream 类可以将格式化数据写入底层 OutputStream 或者直接写入 File 对象. PrintStream 类可以格式化基 ...

  2. laravel-admin(自定义表单与验证)

    场景: 很多时候,由于我们业务场景比较特殊,需要自定义表单,然后框架给我提供了对应表单组建! 案列:以创建一个字段为列 1.在控制器对应的方法中调用表单组建创建表单 public function c ...

  3. 8天入门docker系列 —— 第六天 搭建自己的私有镜像仓库Registry

    这一篇我们来聊聊私有仓库的搭建,其实不管你是通过docker build还是compose的方式进行构建,最终还是要将生成好的镜像push到远程的仓库中,这样多个 平台可以方便的获取你registry ...

  4. vue的懒加载如何实现?

    个人通过查找发现一个比较好用的模块,vue-lazyload 第一步 下载安装这个包    npm install vue-lazyload 第二步 在main.js中引入这个模块 import Vu ...

  5. C++用EGE简单实现别踩白块游戏

    本项目已开源:https://github.com/wmpscc/AvoidBlank 关于EGE 介绍:EGE(Easy Graphics Engine),是windows下的简易绘图库,是一个类似 ...

  6. CCPC2019江西省赛-Problem G.Traffic

    题目描述: /*纯手打题面*/ Avin is observing the cars at a crossroads.He finds that there are n cars running in ...

  7. Git密码修改后,Jenkins job如何批量更新密码?

    很多时候,由于一些原因,更新了Git账号密码:但是,Jenkins构建时,需要通过这个账号去拉取代码:这个时候咋办? 很多同学会说,直接一个个项目更新就OK. 那么,如果是几百个项目.甚至几千个项目呢 ...

  8. 使用SpringSecurity搭建授权认证服务(1) -- 基本demo认证原理

    使用SpringSecurity搭建授权认证服务(1) -- 基本demo 登录认证是做后台开发的最基本的能力,初学就知道一个interceptor或者filter拦截所有请求,然后判断参数是否合理, ...

  9. MyBatis从入门到精通(七):MyBatis动态Sql之choose,where,set标签的用法

    最近在读刘增辉老师所著的<MyBatis从入门到精通>一书,很有收获,于是将自己学习的过程以博客形式输出,如有错误,欢迎指正,如帮助到你,不胜荣幸! 本篇博客主要讲解如何使用choose, ...

  10. XAML与C#与WPF三者到底有什么关系?

    XAML是.NET体系开发程序或者网页时前台编程的一种布局方式或者说开发语言,可以比较自由的用标签的方式进行布局,借鉴了HTML和XML等语言的风格,并且加入了一些动画等的实现.C#则是后台逻辑开发用 ...