感谢朋友支持本博客,欢迎共同探讨交流,由于能力和时间有限,错误之处在所难免,欢迎指正!
如果转载,请保留作者信息。
博客地址:http://blog.csdn.net/gaoxingnengjisuan
邮箱地址:dong.liu@siat.ac.cn
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
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.对于其他情况,不需要进行报警器的分配操作;
下篇博客将会进行继续解析~~~~