感謝朋友支持本博客,歡迎共同探討交流,由於能力和時間有限,錯誤之處在所難免,歡迎指正!
如果轉載,請保留作者信息。
博客地址: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