深挖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. poi 操作Excel 以及大数据量导出

    maven 依赖 (版本必须一致,否则使用SXSSFworkbook 时程序会报错) <dependency> <groupId>org.apache.poi</grou ...

  2. Python连载8-datetime包函数介绍

    一.datetime包(上接连载7内容) 1.函数:datetime (1)用法:输入一个日期,来返回一个datetime类​ (2)格式:datetime.datetime(年,月,日,hour=, ...

  3. test判断条件

      一:Shell test 命令        1.数值测试       参数 说明 -eq 等于则为真 -ne 不等于则为真 -gt 大于则为真 -ge 大于等于则为真 -lt 小于则为真 -le ...

  4. springboot读取本地项目文件

    在读取springBoot+gradle构建的项目时,如果使用传统的FileInputStream读取文件流或者ResourceUtils工具类的方式 File file= ResourceUtils ...

  5. 简单了解HashCode()

    在java的内部类中,计算HashCode通常使用 code = 元素* 31 + 下一个元素 以String为例 public int hashCode() { int h = hash; if ( ...

  6. SQL Server 2012设置某用户对某些表的记录限制其删除操作

    第一步:用sa用户进入SSMS: 第二步:在安全性---用户上面点击右键---"属性": 第三步:在选择页中选择”安全对象“,点击”搜索“,弹出添加对象页面,这里默认为特定对象不用 ...

  7. Scala 学习之路(一)—— Scala简介及开发环境配置

    一.Scala简介 1.1 概念 Scala全称为Scalable Language,即“可伸缩的语言”,之所以这样命名,是因为它的设计目标是希望伴随着用户的需求一起成长.Scala是一门综合了面向对 ...

  8. JavaWeb入门_模仿天猫整站Tmall_SSH实践项目

    Tmall_SSH 技术栈 Struts2 + Hibernate + Spring + Jsp + Tomcat , 是 Java Web 入门非常好的练手项目 效果展示: 模仿天猫前台 模仿天猫后 ...

  9. SpringBoot系列——Logback日志,输出到文件以及实时输出到web页面

    前言 SpringBoot对所有内部日志使用通用日志记录,但保留底层日志实现.为Java Util Logging.Log4J2和Logback提供了默认配置.在不同的情况下,日志记录器都预先配置为使 ...

  10. 关于ArrayList的扩容机制

    关于ArrayList的扩容机制 ArrayList作为List接口常用的一个实现类,其底层数据接口由数组实现,可以保证O(1) 复杂度的随机查找, 在增删效率上不如LinkedList,但是在查询效 ...