感謝朋友支持本博客,歡迎共同探討交流,由於能力和時間有限,錯誤之處在所難免,歡迎指正!
如果轉載,請保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
郵箱地址:[email protected]
PS:最近沒有登錄博客,很多朋友的留言沒有看見,這裏道歉!還有就是本人較少上QQ,可以郵件交流。
ceilometer分佈式報警系統的具體實現(1)
在前面的博客中,我們分析過在/ceilometer/alarm/service.py中實現了類PartitionedAlarmService,它的主要功能是實現了分佈式報警系統服務的啓動和其他操作,當時我們只是從整體上分析了分佈式報警系統的啓動和實現,而分佈式報警系統各個操作的具體實現則是在/ceilometer/alarm/partition/coordination.py中的類PartitionCoordinator中,所以這篇博客將會詳細地分析分佈式報警系統的具體實現,即分析類PartitionCoordinator中各個方法的源碼實現。
1 def _distribute(self, alarms, rebalance)
def _distribute(self, alarms, rebalance):
"""
實現對報警器的分配操作;
如果需要對全部報警器執行重新分配操作,self.coordination_rpc.assign(對所有的報警器進行分配操作):
通過廣播發送執行assign操作的通知給所有的Partition,在所有的Partition執行接收操作;在接收操作中,如果uuid和某Partition相應的uuid值相匹配,則該Partition實現賦值本alarms的ID值到其本地;
如果不需要對全部報警器執行重新分配操作,self.coordination_rpc.allocate(只對部分(新增)的報警器進行分配操作,所以某個Partition上可有多餘1個的報警器):
通過廣播發送執行allocate操作的通知給所有的Partition,在所有的Partition執行接收操作;在接收操作中,如果uuid和某Partition相應的uuid值相匹配,則該Partition實現添加本alarms的ID值到其本地;
"""
verb = 'assign' if rebalance else 'allocate'
"""
根據rebalance的值,來確定所要執行的分配報警器的方法;
如果需要對全部報警器重新分配操作,則調用self.coordination_rpc.assign;
如果不需要對全部報警器重新分配操作,則調用self.coordination_rpc.allocate;
self.coordination_rpc.assign:
通過廣播發送執行assign操作的通知給所有的Partition,
在所有的Partition執行接收操作;
在接收操作中,如果uuid和某Partition相應的uuid值相匹配,
則該Partition實現賦值本alarms的ID值到其本地;
self.coordination_rpc.allocate:
通過廣播發送執行allocate操作的通知給所有的Partition,
在所有的Partition執行接收操作;
在接收操作中,如果uuid和某Partition相應的uuid值相匹配,
則該Partition實現添加本alarms的ID值到其本地;
"""
method = (self.coordination_rpc.assign if rebalance
else self.coordination_rpc.allocate)
LOG.debug(_('triggering %s') % verb)
LOG.debug(_('known evaluators %s') % self.reports)
"""
計算每個evaluator上所要分配的報警器數目;
"""
per_evaluator = int(math.ceil(len(alarms) /
float(len(self.reports) + 1)))
LOG.debug(_('per evaluator allocation %s') % per_evaluator)
"""
獲取所有的evaluator;
對所有的evaluator進行洗牌操作;
"""
evaluators = self.reports.keys()
random.shuffle(evaluators)
offset = 0
"""
遍歷所有的evaluator;
"""
for evaluator in evaluators:
if self.oldest < self.this:
LOG.warn(_('%(this)s bailing on distribution cycle '
'as older partition detected: %(older)s') %
dict(this=self.this, older=self.oldest))
return False
"""
從所有報警器集合中獲取一個報警器;
"""
allocation = alarms[offset:offset + per_evaluator]
"""
調用之前確定的分配方法,實現對報警器的分配操作;
self.coordination_rpc.assign:
通過廣播發送執行assign操作的通知給所有的Partition,
在所有的Partition執行接收操作;
在接收操作中,如果uuid和某Partition相應的uuid值相匹配,
則該Partition實現賦值本alarms的ID值到其本地;
self.coordination_rpc.allocate:
通過廣播發送執行allocate操作的通知給所有的Partition,
在所有的Partition執行接收操作;
在接收操作中,如果uuid和某Partition相應的uuid值相匹配,
則該Partition實現添加本alarms的ID值到其本地;
"""
if allocation:
LOG.debug(_('%(verb)s-ing %(alloc)s to %(eval)s') %
dict(verb=verb, alloc=allocation, eval=evaluator))
method(evaluator.uuid, allocation)
"""
爲下一個報警器的獲取做準備;
"""
offset += per_evaluator
LOG.debug(_('master taking %s for self') % alarms[offset:])
"""
對於本Partition所分配的報警器的實現;
"""
if rebalance:
self.assignment = alarms[offset:]
else:
self.assignment.extend(alarms[offset:])
return True
方法小結:實現對報警器的分配操作;
1.如果需要對全部報警器執行重新分配操作,self.coordination_rpc.assign(對所有的報警器進行分配操作):
通過廣播發送執行assign操作的通知給所有的Partition,在所有的Partition執行接收操作;在接收操作中,如果uuid和某Partition相應的uuid值相匹配,則該Partition實現賦值本alarms的ID值到其本地;
2.如果不需要對全部報警器執行重新分配操作,self.coordination_rpc.allocate(只對部分(新增)的報警器進行分配操作,所以某個Partition上可有多餘1個的報警器):
通過廣播發送執行allocate操作的通知給所有的Partition,在所有的Partition執行接收操作;在接收操作中,如果uuid和某Partition相應的uuid值相匹配,則該Partition實現添加本alarms的ID值到其本地;
2 def _deletion_requires_rebalance(self, alarms)
def _deletion_requires_rebalance(self, alarms):
"""
通過獲取最新已刪除的報警器數據,來確定是否需要執行rebalance操作;
如果已刪除的報警器數據多餘當前報警器數據的五分之一,則返回True,說明需要執行rebalance操作;
"""
# 獲取最新已經刪除的報警器集合;
deleted_alarms = self.last_alarms - set(alarms)
LOG.debug(_('newly deleted alarms %s') % deleted_alarms)
# 存儲最新的已刪除的報警器數據;
self.deleted_alarms.update(deleted_alarms)
# 如果已刪除的報警器數據多餘當前報警器數據的五分之一,則返回True,說明需要執行rebalance操作;
if len(self.deleted_alarms) > len(alarms) / 5:
LOG.debug(_('alarm deletion activity requires rebalance'))
self.deleted_alarms = set()
return True
return False
方法小結:通過獲取最新已刪除的報警器數據,來確定是否需要執行rebalance操作;
如果已刪除的報警器數據多餘當前報警器數據的五分之一,則返回True,說明需要執行rebalance操作;
3 def _is_master(self, interval)
def _is_master(self, interval):
"""
確定當前的partition是否是主控角色;
"""
now = timeutils.utcnow()
if timeutils.delta_seconds(self.start, now) < interval * 2:
LOG.debug(_('%s still warming up') % self.this)
return False
is_master = True
for partition, last_heard in self.reports.items():
delta = timeutils.delta_seconds(last_heard, now)
LOG.debug(_('last heard from %(report)s %(delta)s seconds ago') %
dict(report=partition, delta=delta))
if delta > interval * 2:
del self.reports[partition]
self._record_oldest(partition, stale=True)
LOG.debug(_('%(this)s detects stale evaluator: %(stale)s') %
dict(this=self.this, stale=partition))
self.presence_changed = True
elif partition < self.this:
is_master = False
LOG.info(_('%(this)s sees older potential master: %(older)s')
% dict(this=self.this, older=partition))
LOG.info(_('%(this)s is master?: %(is_master)s') %
dict(this=self.this, is_master=is_master))
return is_master
4 def _master_role(self, assuming, api_client)
def _master_role(self, assuming, api_client):
"""
作爲擁有主控權的partition,根據不同的情況實現不同形式的報警器分配操作;
1.需要整個分佈式報警系統的重平衡操作
如果assuming爲True,說明此報警器爲新進的分佈式報警系統的主控節點(所以需
要整個分佈式報警系統的重平衡操作);
如果sufficient_deletion爲True,說明已刪除的報警器數據多餘當前報警器數據的
五分之一(變化過多,所以需要整個分佈式報警系統的重平衡操作);
如果presence_changed爲True,則說明需要執行整個分佈式報警系統的重平衡操作;
2.對部分報警器(新建立報警器)實現重平衡操作;
3.對於其他情況,不需要進行報警器的分配操作;
"""
"""
通過客戶端獲取當前所有partition的報警器;
"""
alarms = [a.alarm_id for a in api_client.alarms.list()]
"""
獲取新建立的報警器;
當前的報警器集合減去之前的報警器集合,得到新建立的報警器;
"""
created_alarms = list(set(alarms) - self.last_alarms)
LOG.debug(_('newly created alarms %s') % created_alarms)
"""
通過獲取最新已刪除的報警器數據,來確定是否需要執行rebalance操作;
如果已刪除的報警器數據多餘當前報警器數據的五分之一,則返回True,說明需要執
行rebalance操作;
"""
sufficient_deletion = self._deletion_requires_rebalance(alarms)
"""
如果assuming爲True,說明此報警器爲新進的分佈式報警系統的主控節點(所以需要
整個分佈式報警系統的重平衡操作);
如果sufficient_deletion爲True,說明已刪除的報警器數據多餘當前報警器數據的五
分之一(變化過多,所以需要整個分佈式報警系統的重平衡操作);
如果presence_changed爲True,則說明需要執行整個分佈式報警系統的重平衡操作;
"""
# _distribute:實現對報警器的分配操作;
if (assuming or sufficient_deletion or self.presence_changed):
still_ahead = self._distribute(alarms, rebalance=True)
"""
對於新建立報警器,實現對報警器分配操作,不需要進行所有報警器的重新分配操作;
"""
elif created_alarms:
still_ahead = self._distribute(list(created_alarms),
rebalance=False)
"""
對於其他情況,不需要進行報警器的分配操作;
"""
else:
still_ahead = self.this < self.oldest
"""
實現更新報警器的集合;
"""
self.last_alarms = set(alarms)
LOG.info(_('%(this)s not overtaken as master? %(still_ahead)s') %
({'this': self.this, 'still_ahead': still_ahead}))
return still_ahead
方法小結:作爲擁有主控權的partition,根據不同的情況實現不同形式的報警器分配操作;
1.需要整個分佈式報警系統的重平衡操作
如果assuming爲True,說明此報警器爲新進的分佈式報警系統的主控節點(所以需要整個分佈式報警系統的重平衡操作);
如果sufficient_deletion爲True,說明已刪除的報警器數據多餘當前報警器數據的五分之一(變化過多,所以需要整個分佈式報警系統的重平衡操作);
如果presence_changed爲True,則說明需要執行整個分佈式報警系統的重平衡操作;
2.對部分報警器(新建立報警器)實現重平衡操作;
3.對於其他情況,不需要進行報警器的分配操作;
下篇博客將會進行繼續解析~~~~