nova定制調(diào)度算法

以nova kilo版本為例

nova調(diào)度過程分析

之前創(chuàng)建虛擬機流程分析提到過:


#nova/scheduler/manager.py
class SchedulerManager(manager.Manager):
        @messaging.expected_exceptions(exception.NoValidHost)
    def select_destinations(self, context, request_spec, filter_properties):
        '''driver其實就是調(diào)度算法實現(xiàn),由配置文件決定,通常用的比較多的就是filter_scheduler,
        對應(yīng)filter_scheduler.py模塊,該模塊首先通過host_manager拿到所有的計算節(jié)點信息,
        然后通過filters過濾掉不滿足條件的計算節(jié)點,剩下的節(jié)點通過weigh方法計算權(quán)值,
        最后選擇權(quán)值高的作為候選計算節(jié)點返回。nova-scheduler進程結(jié)束。'''
        dests = self.driver.select_destinations(context, request_spec,
            filter_properties)
        return jsonutils.to_primitive(dests)

driver在SchedulerManager 的init方法中定義

class SchedulerManager(manager.Manager):
    def __init__(self, scheduler_driver=None, *args, **kwargs):
        if not scheduler_driver:
            scheduler_driver = CONF.scheduler_driver
        #driver 是通過配置文件中的選項值指定的類來返回的對象
        self.driver = importutils.import_object(scheduler_driver)

在nova的配置文件中:

scheduler_driver=nova.scheduler.filter_scheduler.FilterScheduler

繼續(xù)往下分析:

#nova/scheduler/filter_scheduler.py
class FilterScheduler(driver.Scheduler):
    def select_destinations(self, context, request_spec, filter_properties):
        ...
        # 需要創(chuàng)建的 Instances 的數(shù)量
        num_instances = request_spec['num_instances']
        # 獲取滿足笫一次過濾條件的主機列表 List
        selected_hosts = self._schedule(context, request_spec,
                                        filter_properties)
        # 當(dāng)請求的 Instance 數(shù)量大于合適的主機數(shù)量時,不會創(chuàng)建 Instance 且輸出錯誤信息
        if len(selected_hosts) < num_instances and\
            len(selected_hosts) >= min_instances:
            ...
        elif len(selected_hosts) < min_instances:
            ...
        dests = [dict(host=host.obj.host, nodename=host.obj.nodename,
                      limits=host.obj.limits) for host in selected_hosts]
        ...
        return dests 
        
        
    def _schedule(self, context, request_spec, filter_properties):  
        ...
        #獲取所有Hosts 狀態(tài),主要用來去除不活躍的節(jié)點
        hosts = self._get_all_host_states(elevated)
        #調(diào)用HostManager的get_filtered_hosts方法來選擇可用的計算節(jié)點
        hosts = self.host_manager.get_filtered_hosts(hosts,
                        filter_properties, index=num, context=context)
        ...
        #通過 Weighed 選取最優(yōu) Host
        weighed_hosts = self.host_manager.get_weighed_hosts(hosts,
                    filter_properties, context=context)
        ...
        return selected_hosts

再來看看get_filtered_hosts的調(diào)用過程:

#nova/scheduler/host_manager.py
class HostManager(object):
    def get_filtered_hosts(self, hosts, filter_properties,
            filter_class_names=None, index=0, context=None):
        ...
        if filter_class_names is None:
            filters = self.default_filters
        else:
            filters = self._choose_host_filters(filter_class_names)
        ...
        return self.filter_handler.get_filtered_objects(filters,
                hosts, filter_properties, index, context=context)
        
    def _choose_host_filters(self, filter_cls_names):
        ...
        #將filter_cls_names封裝成列表
        if not isinstance(filter_cls_names, (list, tuple)):
            filter_cls_names = [filter_cls_names]

        good_filters = []
        bad_filters = []
        for filter_name in filter_cls_names:
            if filter_name not in self.filter_obj_map:
                if filter_name not in self.filter_cls_map:
                    bad_filters.append(filter_name)
                    continue
                filter_cls = self.filter_cls_map[filter_name]
                self.filter_obj_map[filter_name] = filter_cls()
            good_filters.append(self.filter_obj_map[filter_name])
        if bad_filters:
            msg = ", ".join(bad_filters)
            raise exception.SchedulerHostFilterNotFound(filter_name=msg)
        return good_filters
        
    def __init__(self):
        self.filter_handler = filters.HostFilterHandler()
        #__init__方法中調(diào)用get_matching_classes方法去加載nova.conf配置文件的scheduler_available_filters屬性設(shè)置的fileter
        filter_classes = self.filter_handler.get_matching_classes(
                CONF.scheduler_available_filters)
        self.filter_cls_map = {cls.__name__: cls for cls in filter_classes}
        self.default_filters = self._choose_host_filters(self._load_filters())
        
    def _load_filters(self):
        return CONF.scheduler_default_filters
        

nova.conf中的相關(guān)配置如下:

scheduler_available_filters=nova.scheduler.filters.all_filters
scheduler_default_filters=RetryFilter,AvailabilityZoneFilter,RamFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter

總結(jié)一下_choose_host_filters的工作流程:

  1. 將filter_cls_names封裝成列表
  2. 依次檢查filter_cls_names中的所有可用的filter列表(個人理解,其檢查過程就是判斷scheduler_default_filters定義的filter能不能在nova/filter/下找到相關(guān)類)
  3. 返回可用filter列表

添加自定義filter

自定義一個filter類,specified_host_filter.py:


from oslo_log import log as logging

from nova.scheduler import filters

LOG = logging.getLogger(__name__)

#任何filter類必須繼承filters.BaseHostFilter類
class SpecifiedHostFilter(filters.BaseHostFilter):
    def __init__(self):
        #通知成功加載SpecifiedHostFilter類
        LOG.info("SpecifiedHostFilter is initialized!")
    
    #host_passes是每個類必須實現(xiàn)的方法,host_state保存了詢問的計算節(jié)點的信息
    #filter_properties保存了一些幫助nvoa scheduler完成調(diào)度的信息
    def host_passes(slef, host_state, filter_properties):
        #獲取客戶端要求的計算節(jié)點主機名
        scheduler_hints = filter_properties.get('scheduler_hints',{})
        requested_host = scheduler_hints.get('requested_host',None)
        #如果客戶提供了要求的計算節(jié)點,則檢查當(dāng)前計算節(jié)點與客戶要求的節(jié)點是否匹配
        if requested_host:
            return requested_host == host_state.host
        #如果客戶沒有提供要求的計算節(jié)點,則返回真
        return True

將自定義filter放在nova目錄下,形成下面的目錄結(jié)構(gòu):

├── scheduler
├── myproject
│   ├── __init__.py
│   ├── specified_host_filter.py

修改nova.conf配置文件,

scheduler_available_filters=nova.scheduler.filters.all_filters
scheduler_available_filters=nova.myproject.specified_host_filter.SpecifiedHostFilter
scheduler_default_filters=RetryFilter,AvailabilityZoneFilter,RamFilter,ComputeFilter,ComputeCapabilitiesFilter,ImagePropertiesFilter,SpecifiedHostFilter

重啟nova-scheduler服務(wù)

客戶端測試

使用rdo快速搭建openstack-allinone環(huán)境,詳情見官網(wǎng)

在specified_host_filter.py中打斷點后,停止nova-scheduler服務(wù),手動啟動scheduler服務(wù):

/usr/bin/python /usr/bin/nova-scheduler --config-file /etc/nova/nova.conf --logfile /var/log/nova/nova-scheduler.log

創(chuàng)建一臺虛擬機:

openstack server create --flavor m1.tiny --image cirros --nic net-id=4eace7c7-ec56-4e12-9a05-fc70a0887220 --security-group default ----hint requested_host=no-such-host test

執(zhí)行到斷點處:

(Pdb) l
  8         def __init__(self):
  9             LOG.info("SpecifiedHostFilter is initialized!")
 10
 11         def host_passes(slef, host_state, filter_properties):
 12             import pdb; pdb.set_trace()
 13  ->         scheduler_hints = filter_properties.get('scheduler_hints',{})
 14             requested_host = scheduler_hints.get('requested_host',None)
 15             if requested_host:
 16                 return requested_host ==host_state.host
 17             return True
[EOF]
Pdb) n
-> requested_host = scheduler_hints.get('requested_host',None)
(Pdb) p scheduler_hints
{u'requested_host': u'no-such-host'}
(Pdb) n
-> if requested_host:
(Pdb) n
-> return requested_host ==host_state.host
(Pdb) p requested_host
u'no-such-host'
(Pdb) p host_state.host
u'openstack'

因為我們傳的'no-such-host'和可用的主機'openstack'不相等,所以日志中看到這樣的消息:

2017-05-02 18:19:42.417 13453 INFO nova.myproject.specified_host_filter [-] SpecifiedHostFilter is initialized!
2017-05-02 18:21:54.628 13453 INFO nova.filters [req-d120d748-eb65-4b86-a5ed-22673ea76a52 00ce1cf60c3a4df2842437b5c23d35f6 67ee8dfa658e43b2b1a3d8108f624a95 - - -] Filter SpecifiedHostFilter returned 0 hosts

如果我們不傳--hint參數(shù) 或者----hint requested_host=openstack ,虛擬機創(chuàng)建以后狀態(tài)為Active

參考:

JiYou

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容