深挖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. Qt中使用QSqlDatabase::removeDatabase()的正确方法 good

    如果你用过Qt的QSqlDatabase的话,多半会对下面的警告信息感兴趣: QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_defau ...

  2. Dedecms 中,获取某一栏目所有子栏目

    以前从来没写过递归(其实想想,对算法完全没概念),刚好有这个需求,试着写了一下,发现也挺容易的,特别记录一下. 数据库是dedecms默认的,dede_arctype是保存栏目的表,reid是栏目的父 ...

  3. Codility---MaxSliceSum

    Task description A non-empty zero-indexed array A consisting of N integers is given. A pair of integ ...

  4. HTTP Post之multipart/form-data和application/x-www-form-urlencoded

    关于HttpPost,有这样两种可Post的数据载体,分别是MultipartEntity和UrlEncodedFormEntity,对这两者的共性和异性做如下解释和备忘: 共性: 1.都属于HTTP ...

  5. linux下安装Nginx1.16.0

    因为最近在倒腾linux,想安装新版本的nginx,找了一圈教程没有找到对应的教程,在稍微倒腾了一会之后终于成功的安装了最新版. 服务器环境为centos,接下来是详细步骤: 安装必要依赖插件 yum ...

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

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

  7. ph模拟登录获取信息

    cURL 是一个功能强大的PHP库,使用PHP的cURL库可以简单和有效地抓取网页并采集内容,设置cookie完成模拟登录网页,curl提供了丰富的函数,开发者可以从PHP手册中获取更多关于cURL信 ...

  8. 秒懂Hash算法(一):什么是Hash

    Hash函数 在一般的线性表.树结构中,数据的存储位置是随机的,不像数组可以通过索引能一步查找到目标元素.为了能快速地在没有索引之类的结构中找到目标元素,需要为存储地址和值之间做一种映射关系h(key ...

  9. You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'wher id = 41' at line 1

    where 没有打完整

  10. kafka入门(三)备份

    一.相关概念 备份相关的角色 Kafka消息备份分三个角色:分别是Leader副本.Follower副本.ISR集合 Leader副本 负责直接响应client端的读写请求,即和生产者和消费者直接对接 ...