nova定制調度算法

以nova kilo版本為例

nova調度過程分析

之前創建虛擬機流程分析提到過:


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

繼續往下分析:

#nova/scheduler/filter_scheduler.py
class FilterScheduler(driver.Scheduler):
    def select_destinations(self, context, request_spec, filter_properties):
        ...
        # 需要創建的 Instances 的數量
        num_instances = request_spec['num_instances']
        # 獲取滿足笫一次過濾條件的主機列表 List
        selected_hosts = self._schedule(context, request_spec,
                                        filter_properties)
        # 當請求的 Instance 數量大于合適的主機數量時,不會創建 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 狀態,主要用來去除不活躍的節點
        hosts = self._get_all_host_states(elevated)
        #調用HostManager的get_filtered_hosts方法來選擇可用的計算節點
        hosts = self.host_manager.get_filtered_hosts(hosts,
                        filter_properties, index=num, context=context)
        ...
        #通過 Weighed 選取最優 Host
        weighed_hosts = self.host_manager.get_weighed_hosts(hosts,
                    filter_properties, context=context)
        ...
        return selected_hosts

再來看看get_filtered_hosts的調用過程:

#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__方法中調用get_matching_classes方法去加載nova.conf配置文件的scheduler_available_filters屬性設置的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中的相關配置如下:

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

總結一下_choose_host_filters的工作流程:

  1. 將filter_cls_names封裝成列表
  2. 依次檢查filter_cls_names中的所有可用的filter列表(個人理解,其檢查過程就是判斷scheduler_default_filters定義的filter能不能在nova/filter/下找到相關類)
  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是每個類必須實現的方法,host_state保存了詢問的計算節點的信息
    #filter_properties保存了一些幫助nvoa scheduler完成調度的信息
    def host_passes(slef, host_state, filter_properties):
        #獲取客戶端要求的計算節點主機名
        scheduler_hints = filter_properties.get('scheduler_hints',{})
        requested_host = scheduler_hints.get('requested_host',None)
        #如果客戶提供了要求的計算節點,則檢查當前計算節點與客戶要求的節點是否匹配
        if requested_host:
            return requested_host == host_state.host
        #如果客戶沒有提供要求的計算節點,則返回真
        return True

將自定義filter放在nova目錄下,形成下面的目錄結構:

├── 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服務

客戶端測試

使用rdo快速搭建openstack-allinone環境,詳情見官網

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

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

創建一臺虛擬機:

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

執行到斷點處:

(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參數 或者----hint requested_host=openstack ,虛擬機創建以后狀態為Active

參考:

JiYou

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,622評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,716評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,746評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,991評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,706評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,036評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,029評論 3 450
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,203評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,725評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,451評論 3 361
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,677評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,161評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,857評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,266評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,606評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,407評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,643評論 2 380

推薦閱讀更多精彩內容