Ceilometer項目源碼分析----ceilometer-alarm-evaluator服務的初始化和啓動

感謝朋友支持本博客,歡迎共同探討交流,由於能力和時間有限,錯誤之處在所難免,歡迎指正!

如果轉載,請保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
郵箱地址:[email protected]

PS:最近沒有登錄博客,很多朋友的留言沒有看見,這裏道歉!還有就是本人較少上QQ,可以郵件交流。


ceilometer-alarm-evaluator服務的初始化和啓動

    本篇博客將解析服務組件ceilometer-alarm-evaluator的初始化和啓動操作,這個服務組件即ceilometer報警服務;來看方法/ceilometer/cli.py----def alarm_evaluator,這個方法即實現了ceilometer-alarm-evaluator服務的初始化和啓動操作。

def alarm_evaluator():
    """
    加載並啓動SingletonAlarmService服務(單例報警服務);
    報警服務系統:SingletonAlarmService和PartitionedAlarmService;
    默認報警服務:ceilometer.alarm.service.SingletonAlarmService;
    如果要應用分佈式報警系統,則需要在這裏修改配置文件中的參數;
    """
    service.prepare_service()
    
    """
    launch:加載並啓動SingletonAlarmService服務,最終調用了服務的start方法實現服務的啓動;
    配置文件定義了默認報警服務:ceilometer.alarm.service.SingletonAlarmService
    SingletonAlarmService:單例的報警服務;
    """
    eval_service = importutils.import_object(cfg.CONF.alarm.evaluation_service)
    os_service.launch(eval_service).wait(
方法小結:
    1.報警服務系統:
      SingletonAlarmService和PartitionedAlarmService;
    2.默認報警服務:
      ceilometer.alarm.service.SingletonAlarmService;
    3.如果要應用分佈式報警系統,則需要在這裏修改配置文件中的參數;


1 單例報警服務SingletonAlarmService的初始化和啓動操作

1.1 SingletonAlarmService類初始化操作

    類SingletonAlarmService的初始化操作主要完成了兩部分內容:

    * 加載命名空間ceilometer.alarm.evaluator中的所有插件;

      ceilometer.alarm.evaluator =

          threshold = ceilometer.alarm.evaluator.threshold:ThresholdEvaluator

          combination = ceilometer.alarm.evaluator.combination:CombinationEvaluator

      即描述了報警器狀態的評估判定的兩種模式:聯合報警器狀態評估和單一報警器狀態評估;

    * 建立線程池,用於後續報警器服務中若干操作的運行;


class SingletonAlarmService----def __init__

class SingletonAlarmService(AlarmService, os_service.Service):
    def __init__(self):
        super(SingletonAlarmService, self).__init__()
        """
        _load_evaluators:
        這裏得到的就是加載命名空間ceilometer.alarm.evaluator中的所有插件;
        namespace = ceilometer.alarm.evaluator
            ceilometer.alarm.evaluator =
            threshold = ceilometer.alarm.evaluator.threshold:ThresholdEvaluator
            combination = ceilometer.alarm.evaluator.combination:CombinationEvaluator
        """
        self._load_evaluators()
        self.api_client = None


class Service----def __init__

class Service(object):
    def __init__(self, threads=1000):
        self.tg = threadgroup.ThreadGroup(threads)
        # signal that the service is done shutting itself down:
        self._done = event.Event()


class AlarmService----def _load_evaluators

class AlarmService(object):
    EXTENSIONS_NAMESPACE = "ceilometer.alarm.evaluator"

    def _load_evaluators(self):
        """
        這裏得到的就是加載命名空間ceilometer.alarm.evaluator中的所有插件;
        namespace = ceilometer.alarm.evaluator
        ceilometer.alarm.evaluator =
        threshold = ceilometer.alarm.evaluator.threshold:ThresholdEvaluator
        combination = ceilometer.alarm.evaluator.combination:CombinationEvaluator
        """
        self.evaluators = extension.ExtensionManager(
        namespace=self.EXTENSIONS_NAMESPACE,
        invoke_on_load=True,
        invoke_args=(rpc_alarm.RPCAlarmNotifier(),)
        )
        # 這裏得到的就是上面所加載的命名空間ceilometer.alarm.evaluator中的所有插件;
        self.supported_evaluators = [ext.name for ext in
                                     self.evaluators.extensions]

1.2 SingletonAlarmService類啓動操作

    類的啓動操作實現了單例報警器服務SingletonAlarmService的啓動操作;
    按照一定時間間隔實現循環執行方法self._evaluate_assigned_alarms,方法self._evaluate_assigned_alarms實現獲取alarm集合,針對每一個報警器,實現根據報警器模式的類型(threshold和combination),來實現單一報警器模式或者聯合報警器模式的評估判定;


class SingletonAlarmService----def start

def start(self):
    """
    單例報警器服務SingletonAlarmService的啓動操作;
    按照一定時間間隔實現循環執行方法self._evaluate_assigned_alarms;
    獲取alarm集合,針對每一個報警器,實現根據報警器模式的類型(threshold和combination),來實現單一報警器模式或者聯合報警器模式的評估判定;
    """
    super(SingletonAlarmService, self).start()
    if self.evaluators:
        """
        評估週期60s;
        """
        interval = cfg.CONF.alarm.evaluation_interval
            
        # add_timer:按照一定時間間隔實現循環執行方法self._evaluate_assigned_alarms;
        # _evaluate_assigned_alarms:
        # 先獲取alarm集合,對每一個alarm,調用_evaluate_alarm方法;
        # 針對每一個報警器,實現根據報警器的類型(threshold和combination),來實現:
        # 單一報警器狀態的評估判定;
        # 聯合報警器狀態的評估判定;
        self.tg.add_timer(
            interval,
            self._evaluate_assigned_alarms,
            0)
    # Add a dummy thread to have wait() working
    self.tg.add_timer(604800, lambda: None)

class AlarmService----def _evaluate_assigned_alarms

    這個方法實現獲取當前部分的所有報警器,對每一個報警器進行報警觸發的評估判定;
    1.獲取當前部分的所有報警器;
    2.針對每一個報警器,實現根據報警器模式的類型(threshold和combination),來實現單一報警器模式或者聯合報警器模式的評估判定;

def _evaluate_assigned_alarms(self):
    """
    獲取當前部分的所有報警器,對每一個報警器進行報警觸發的評估判定;
    1.獲取當前部分的所有報警器;
    2.針對每一個報警器,實現根據報警器模式的類型(threshold和combination),
      來實現單一報警器模式或者聯合報警器模式的評估判定;
    """
    try:
        # 獲取所有報警器列表;
        # 對於單例報警器:通過指定客戶端通過http協議發送GET請求獲取分配給當前部分的報警器;
        alarms = self._assigned_alarms()
        LOG.info(_('initiating evaluation cycle on %d alarms') %
                 len(alarms))
            
        # 遍歷所有的報警器;
        # 針對每一個報警器,實現根據報警器的類型(threshold和combination),來實現:
        # 單一報警器狀態的評估判定;
        # 聯合報警器狀態的評估判定;
        for alarm in alarms:
            self._evaluate_alarm(alarm)
    except Exception:
        LOG.exception(_('alarm evaluation cycle failed'))

2 分佈式報警服務PartitionedAlarmService的初始化和啓動操作

2.1 PartitionedAlarmService類初始化操作

    PartitionedAlarmService類初始化操作SingletonAlarmService類初始化操作內容大致是相同的,同樣主要完成了兩部分內容:

    * 加載命名空間ceilometer.alarm.evaluator中的所有插件;

      ceilometer.alarm.evaluator =

          threshold = ceilometer.alarm.evaluator.threshold:ThresholdEvaluator

          combination = ceilometer.alarm.evaluator.combination:CombinationEvaluator

      即描述了報警器狀態的評估判定的兩種模式:聯合報警器狀態評估和單一報警器狀態評估;

    * 建立線程池,用於後續報警器服務中若干操作的運行;

    * 初始化分佈式報警協議實現類PartitionCoordinator;


class PartitionedAlarmService----def __init__

class PartitionedAlarmService(AlarmService, rpc_service.Service):
    """
    分佈式報警器系統服務;
    """
    def __init__(self):
        super(PartitionedAlarmService, self).__init__(
            cfg.CONF.host,
            cfg.CONF.alarm.partition_rpc_topic,
            self
        )
        """
        加載命名空間ceilometer.alarm.evaluator中的所有插件;
        namespace = ceilometer.alarm.evaluator
            ceilometer.alarm.evaluator =
            threshold = ceilometer.alarm.evaluator.threshold:ThresholdEvaluator
            combination = ceilometer.alarm.evaluator.combination:CombinationEvaluator
        """
        self._load_evaluators()
        self.api_client = None
        self.partition_coordinator = coordination.PartitionCoordinator()

class Service----def __init__
class Service(object):
    def __init__(self, threads=1000):
        self.tg = threadgroup.ThreadGroup(threads)
        # signal that the service is done shutting itself down:
        self._done = event.Event()

class AlarmService----def _load_evaluators

class AlarmService(object):
    EXTENSIONS_NAMESPACE = "ceilometer.alarm.evaluator"

    def _load_evaluators(self):
        """
        這裏得到的就是加載命名空間ceilometer.alarm.evaluator中的所有插件;
        namespace = ceilometer.alarm.evaluator
        ceilometer.alarm.evaluator =
        threshold = ceilometer.alarm.evaluator.threshold:ThresholdEvaluator
        combination = ceilometer.alarm.evaluator.combination:CombinationEvaluator
        """
        self.evaluators = extension.ExtensionManager(
        namespace=self.EXTENSIONS_NAMESPACE,
        invoke_on_load=True,
        invoke_args=(rpc_alarm.RPCAlarmNotifier(),)
        )
        # 這裏得到的就是上面所加載的命名空間ceilometer.alarm.evaluator中的所有插件;
        self.supported_evaluators = [ext.name for ext in
                                     self.evaluators.extensions]

2.2 PartitionedAlarmService類啓動操作

分佈式報警器系統服務分佈式報警器系統服務的啓動和運行,按照一定的時間間隔週期性的執行以下操作:
1.實現廣播當前partition的存在性的存在性到所有的partition(包括uuid和優先級信息);
2.實現定期檢測主控權角色;確定當前的partition是否是主控角色;
  如果爲擁有主控權的partition,則根據不同的情況實現不同形式的報警器分配操作;
  情況1:所有報警器都要實現重新分配操作;
  情況2:只有新建立的報警器需要實現分配操作;
3.獲取alarm集合,對每一個alarm,調用_evaluate_alarm方法;
  針對每一個報警器,實現根據報警器的類型(threshold和combination),來實現:
  單一報警器模式或者聯合報警器模式的評估判定;


class PartitionedAlarmService----def start

def start(self):
    """
    分佈式報警器系統服務分佈式報警器系統服務的啓動和運行;
    按照一定的時間間隔週期性的執行以下操作:
    1.實現廣播當前partition的存在性的存在性到所有的partition
    (包括uuid和優先級信息);
    2.實現定期檢測主控權角色;確定當前的partition是否是主控角色;
      如果爲擁有主控權的partition,則根據不同的情況實現不同形式的報警器分配操作;
      情況1:所有報警器都要實現重新分配操作;
      情況2:只有新建立的報警器需要實現分配操作;
    3.獲取alarm集合,對每一個alarm,調用_evaluate_alarm方法;
      針對每一個報警器,實現根據報警器的類型(threshold和combination),來實現:
      單一報警器模式或者聯合報警器模式的評估判定;
    """
    # 啓動PartitionedAlarmService服務;
    super(PartitionedAlarmService, self).start()
    if self.evaluators:
        """
        報警評估週期60s;
        """
        eval_interval = cfg.CONF.alarm.evaluation_interval
            
        """
        self.tg = threadgroup.ThreadGroup(1000)
        按照一定時間間隔實現循環執行方法self.partition_coordinator.report_presence;
        通過方法fanout_cast實現廣播當前partition的存在性的存在性到所有的partition(包括uuid和優先級信息);
        """
        self.tg.add_timer(
            eval_interval / 4, # 15s
            self.partition_coordinator.report_presence,
            0)
            
        """
        按照一定時間間隔實現循環執行方法self.partition_coordinator.check_mastership;
        self.partition_coordinator.check_mastership:
        實現定期檢測主控權角色;
        確定當前的partition是否是主控角色;
        如果爲擁有主控權的partition,則根據不同的情況實現不同形式的報警器分配操作;
        """
        self.tg.add_timer(
            eval_interval / 2, # 30s
            self.partition_coordinator.check_mastership,
            eval_interval,     # 60s
            # _client:構建或重新使用一個經過驗證的API客戶端;
            *[eval_interval, self._client])
            
        """
        add_timer:按照一定時間間隔實現循環執行方法self._evaluate_assigned_alarms;
        self._evaluate_assigned_alarms:
        先獲取alarm集合,對每一個alarm,調用_evaluate_alarm方法;
        針對每一個報警器,實現根據報警器的類型(threshold和combination),來實現:
        單一報警器狀態的評估判定;
        聯合報警器狀態的評估判定;
        """
        self.tg.add_timer(
            eval_interval,     # 60s
            # 執行報警器的評估操作;
            self._evaluate_assigned_alarms,
            eval_interval)
        
    # Add a dummy thread to have wait() working
    self.tg.add_timer(604800, lambda: None)

class Service(service.Service)----def start

    因爲這裏實現的是分佈式報警系統,涉及到節點服務間的消息通信,所以這裏應用RPC消息隊列實現服務間的通信,進行相關的初始化操作;

class Service(service.Service):
    def start(self):
        """
        爲RPC通信建立到信息總線的連接;
        1.建立指定類型的消息消費者;       
        2.執行方法initialize_service_hook;
        3.啓動協程實現等待並消費處理隊列中的消息;
        """
        super(Service, self).start()

        """
        爲RPC通信建立到信息總線的連接;
        建立一個新的連接,或者從連接池中獲取一個;
        """
        self.conn = rpc.create_connection(new=True)
        LOG.debug(_("Creating Consumer connection for Service %s") %
                  self.topic)

        """
        RpcDispatcher:RPC消息調度類;
        """
        dispatcher = rpc_dispatcher.RpcDispatcher([self.manager],
                                                  self.serializer)

        # Share this same connection for these Consumers
        """
        create_consumer:建立指定類型的消息消費者(fanout or topic);
        1.創建以服務的topic爲路由鍵的消費者;
        2.創建以服務的topic和本機名爲路由鍵的消費者
          (基於topic&host,可用來接收定向消息);
        3.fanout直接投遞消息,不進行匹配,速度最快
          (fanout類型,可用於接收廣播消息);
        """
        self.conn.create_consumer(self.topic, dispatcher, fanout=False)
        node_topic = '%s.%s' % (self.topic, self.host)
        self.conn.create_consumer(node_topic, dispatcher, fanout=False)
        self.conn.create_consumer(self.topic, dispatcher, fanout=True)

        # Hook to allow the manager to do other initializations after
        # the rpc connection is created.
        """
        在消息消費進程啓動前,必須先聲明消費者;
        建立一個'topic'類型的消息消費者;
        根據消費者類(TopicConsumer)和消息隊列名稱
        (pool_name:  ceilometer.collector.metering)
        以及指定主題topic(metering)建立消息消費者,並加入消費者列表;
        """
        if callable(getattr(self.manager, 'initialize_service_hook', None)):
            self.manager.initialize_service_hook(self)

        """
        啓動消費者線程;
        consume_in_thread用evelent.spawn創建一個協程一直運行;
        等待消息,在有消費到來時會創建新的協程運行遠程調用的函數;
        啓動協程實現等待並消費處理隊列中的消息;
        """
        self.conn.consume_in_thread()

class PartitionedAlarmService----def initialize_service_hook

class PartitionedAlarmService(AlarmService, rpc_service.Service):
    def initialize_service_hook(self, service):
        LOG.debug(_('initialize_service_hooks'))
        
        # create_worker:建立一個'topic'類型的消息消費者;
        # 指定主題topic(alarm_partition_coordination)和隊列名稱pool_name(ceilometer.alarm.alarm_partition_coordination);
        self.conn.create_worker(
            # alarm_partition_coordination
            cfg.CONF.alarm.partition_rpc_topic,
            rpc_dispatcher.RpcDispatcher([self]),
            # ceilometer.alarm.alarm_partition_coordination
            'ceilometer.alarm.' + cfg.CONF.alarm.partition_rpc_topic,
        )
    至此,ceilometer-alarm-evaluator服務的初始化和啓動操作分析完成。


附錄:python的多重父類繼承

    在上面的分析中,我們看到在服務初始化和啓動的過程中,若干方法都是多重父類繼承,這裏需要注意的是父類方法的搜索順序;實際上python經典類的父類方法搜索順序是深度優先,而python新式類的父類方法搜索順序是廣度優先;

    我寫了一個小小的測試程序,來看新式類的父類方法搜索順序:

class A(object):
    def start(self):
        print 'A-start'

class B0(A):
    def start(self):
        super(B0,self).start()
        print 'B0-start'

class B1(A):
    def start(self):
        super(B1,self).start()
        print 'B1-start'

class C(B0,B1):
    def start(self):
        super(C,self).start()
        print 'C-start'

TEST = C()
TEST.start()

輸出爲:
A-start
B1-start
B0-start
C-start
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章