天天看點

OpenStack oslo_config 實作及使用技術探讨一、簡介二、cfg.py解析三、引發思考

一、簡介

衆所周知,oslo_config是openstack架構下各服務加載配置檔案(.conf)所使用的通用庫,配置檔案一般放在/etc目錄的工程目錄下,oslo_config一般是在服務啟動時,提前加載配置資料到記憶體中,之後供服務使用;此處不啰嗦太多,主要還是探讨oslo_config cfg.py檔案的設計優點。

二、cfg.py解析

class ConfigOpts(collections.Mapping):
    def __init__(self):
        pass # 初始化代碼省略

    ...

    def __clear_cache(f):
        pass

    def __call__(self, ...):
        pass

    def __getattr__(self, name):
        pass

    def __getitem__(self, key):
        pass

    def __iter__(self):
        pass

    @__clear_cache
    def clear(self):
        pass

CONF = ConfigOpts()
           

以上核心代碼全部省,請查閱以上隻分析這麼設計的好處:

  • 繼承collections.Mapping,collections.Mapping為一個抽象map類,繼承此類必須實作這幾個抽象方法:__getitem__, __iter__, __len__,并且繼承了dict一些通用方法,将ConfigOpts變成了一個字典類,可以像使用dict函數一樣使用ConfigOpts建立的對象。
  • __init__中并未有傳參來初始化變量,但是同步實作了__calll__,這麼設計是為了之後使用單例設計模式埋下伏筆,程式的末尾CONF對象可以像函數一樣調用初始化内部參數,隻要在一處初始化之後,其餘子產品直接from cfg import CONF就可以直接使用這個執行個體對象,CONF這個執行個體對象就會一直加載在記憶體中,直到服務程序結束,很友善其餘線程使用,并且不需要加線程鎖來避免高并發引來的資料競争問題 。
  • __getattr__重實作,可以将CONF執行個體擷取key值時,直接使用CONF.key_name就可以擷取,而不用使用CONF["key_name"],簡化了資料擷取操作;實際上通過CONF["key_name"]擷取value值時,調用的__getitem__方法,而__getitem__方法内部函數調用__getattr__擷取的值。
  • __iter__将CONF對象周遊時變成一個疊代器對象,有助于提升性能。
  • __clear_cache實作成為一個裝飾器,在調用clear方式的時候使用;ConfigOpts的緩存是在get操作擷取key的value值時使用,将每次擷取的key與value值緩存到一個字典中,在之後的調用中先從字典中直接擷取,此處代碼未展示出來,想要看的可以看源碼。

注意:剛才說了,此種設計可以了解成一種僞單例設計模式,但是初始化CONF時必須保證是在服務剛啟動,其餘子產品未加載CONF中的數值時進行

三、引發思考

oslo_config用來加載配置項,但是一般配置項在使用中途,都有可能更換配置項的參數值,但是更新之後,服務中加載的配置項還是舊的值,這如何處理?

    思考:由于oslo_config加載的配置項資料在記憶體中,使用其餘的服務修改conf檔案内容,确實不好對記憶體中的資料做修改;此處oslo_config将配置項的資料直接加載在記憶體中供服務使用,我覺得是從兩方面考量的,一個是一般配置項資料本身比較少,加載在記憶體中也占用不了太大空間;第二個是一般配置項資料,服務會頻繁使用,存放在記憶體資料速度會很快,提升性能;但是缺點就是如果配置項中的資料如果在服務運作途中發生變更,在不重新開機服務的前提下确實不好處理;

從性能方面考慮感覺可以有如下兩種方案可以解決此問題:

  • 修改配置項之後,立馬重新開機服務,這我感覺是一種比較挫的方法
  • 将修改後的配置項寫入memcache或者redis中,每次從CONF中擷取數值時,先校驗redis中是否有值,如果Redis中有值的話,更新CONF中的值,将Redis中的值移除,我感覺這種方式可以解決此種問題,而且不用重新開機服務