Ceilometer項目源碼分析----ceilometer分佈式報警系統的具體實現(1)

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

如果轉載,請保留作者信息。
博客地址: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.對於其他情況,不需要進行報警器的分配操作;


下篇博客將會進行繼續解析~~~~

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