深挖Openstack Nova - Scheduler調度策略


深挖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
  3.  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM