ceilometer监控源码分析之任务队列
来源:互联网 发布:精易编程助手生成模块 编辑:程序博客网 时间:2024/05/22 07:43
ceilometer监控源码分析之任务队列
场景描述:
ceilometer(这里仅指监控任务)在每个宿主机上运行,读取/etc/ceilometer/pipeline.yaml中配置定时执行监控任务。
pipeline.yaml内容如下:
图注:该图中有三个监控项,分别是heartbeat, cpu, memory,interval表示定时间隔。
代码分析:
( 一 )
故事从/ceilometer/agent/base.py 讲起
openstack项目通常的结构是manage+instance。base.py下有两个关键的类,一个是AgentManager,一个是PollingTask.
1. PollingTask
实现Task的类,主要函数是 poll_and_publish (),该函数实现了从获取监控数据至发送数据的全过程。
2. AgentManager
该类继承os_service, 作为进程入口,持有且管理Task,主要函数是 start()
def start(self): self.pipeline_manager = publish_pipeline.setup_pipeline() self.partition_coordinator.start() self.join_partitioning_groups() # allow time for coordination if necessary delay_start = self.partition_coordinator.is_active() # set shuffle time before polling task if necessary delay_polling_time = random.randint( 0, cfg.CONF.shuffle_time_before_polling_task) for interval, task in six.iteritems(self.setup_polling_tasks()): delay_time = (interval + delay_polling_time if delay_start else delay_polling_time) self.tg.add_timer(interval, self.interval_task, initial_delay=delay_time, task=task) self.tg.add_timer(cfg.CONF.coordination.heartbeat, self.partition_coordinator.heartbeat)
代码注释:
- pipeline_manager从pipeline.yaml文件解析出需要监控的项,封装为interval,task的二元组
- self.tg 实例化一个线程池,实现在/ceilometer/openstack/common/threadgroup.py
- self.interval_task 方法是调用每一个task类中的poll_and_publish()
def poll_and_publish(self): cache = {} discovery_cache = {} for source_name in self.pollster_matches: with self.publishers[source_name] as publisher: for pollster in self.pollster_matches[source_name]: try: samples = list(pollster.obj.get_samples( manager=self.manager, cache=cache, resources=polling_resources )) publisher(samples) except plugin_base.PollsterPermanentError as err: LOG.error(_( 'Prevent pollster %(name)s for ' 'polling source %(source)s anymore!') % ({'name': pollster.name, 'source': source_name})) self.resources[key].blacklist.append(err.fail_res)
代码注释:
- 只摘抄了核心代码
- samples = list() 是调用pollster.obj的get_samples获取每一个vm的监控数据,并返回一个list。
- publisher() 将获取的监控数据,一起发送。
小结:到目前为止,ceilometer启动服务后,会读取配置拿到需要监控的监控项,然后针对每一项起一个线程去执行定时任务。任务内容是获取宿主机上所有虚拟机监控信息,并发送。
( 二 )
/ceilometer/openstack/common/threadgroup.py
该文件下有两个类,一个是 ThreadGroup,一个是 Thread。
- Thread 主要是对greenthread简单的封装,并将threadgroup作为类变量。
- ThreadGroup 实例化一个eventlet的greenpool.封装控制pool的常规操作。
上一小结第一个代码片段中,我们通过 self.tg.add_timer() 将每一个pipeline任务加入线程池。
def add_timer(self, interval, callback, initial_delay=None, *args, **kwargs): pulse = loopingcall.FixedIntervalLoopingCall(callback, *args, **kwargs) pulse.start(interval=interval, initial_delay=initial_delay) self.timers.append(pulse)
@param: interval 定时任务执行间隔
@param: callback 上一小节分析的poll_and_publish方法
这节代码关键是pulse是个什么?
loopingcall.FixedIntervalLoopingCall里面封装了一个greenthread,将callback作为参数传进去,并生成一个新的协程,其基本方法就是 start(), stop() 和 wait()
def _inner(): try: while self._running: start = _ts() self.f(*self.args, **self.kw) end = _ts() if not self._running: break delay = end - start - interval if delay > 0: LOG.warn(_LW('task %(func_name)r run outlasted ' 'interval by %(delay).2f sec'), {'func_name': self.f, 'delay': delay}) greenthread.sleep(-delay if delay < 0 else 0)
代码注释:
- self.f 还是之前分析的 poll_and_publish(),service的主要 job
- delay是计算 poll_and_publish() 执行时间差,并减去任务执行间隔时间
- delay取反后,就是任务需要sleep的准确时间。
小结:至此,就是服务主循环实现的过程。对于多个pipeline,我们启动多个协程,各自计时,实现获取数据及推送功能。
( 三 )
回到 /ceilometer/agent/base.py
我们来看一下如何获取一台宿主机上,所有虚拟机监控数据。在这里我们以 cpu负载为例。
如果忘记下面这段代码可以回顾下第一小节。
samples = list(pollster.obj.get_samples( manager=self.manager, cache=cache, resources=polling_resources))
我们通过这个得到监控数据的list。也就是 pollster.obj.get_samples() 会返回所有监控数据。
def get_samples(self, manager, cache, resources): resources_no_repeat = [] for r in resources: uniq_id = BaseParallelPollster.get_resource_identity(r) # avoid re-add task.If not those most time-consuming task will # occupy all thread, other waiting tasks cannot be attached # to a thread. if uniq_id not in BaseParallelPollster.uniq_ids: BaseParallelPollster.uniq_ids.add(uniq_id) resources_no_repeat.append(r) self._collector.add_tasks( [PoolTask( self.inspector_resource_info, args=[r, manager, cache], callback=self.handle_result, ex_callback=self.handle_exception) for r in resources_no_repeat]) success_taskes = self._collector.wait_for_result(self._default_timeout) result = [] for _t in success_taskes: result += self.convert_info_2_sample(_t.result, *_t.args) return result.__iter__()
代码注释:
- resources是通过libvirt接口获取该宿主机上所有vm的instances。
- self._collector 显然是针对每一个vm实例,将其放入线程池中,获取其监控数据。
- success_taskes 是拿到所有运行结果。
- self.convert_info_2_sample() 将数据转换为我们需要的格式。
self._collector.add_tasks() 是在ResultCollector类中,主要方法是 add_tasks , start_exec_tasks 和 wait_for_result。
主要分析 wait_for_result 方法
def wait_for_result(self, time_out, check_interval=0.1): assert check_interval > 0 assert check_interval < time_out # start all task. self.start_exec_tasks() # wait for all task for result. time_start = int(time.time()) time.sleep(0.1) while time.time() - time_start < time_out and not self._is_finished(): time.sleep(check_interval) return [_t for _t in self._tasks if _t.result]
代码注释:
- 如果等待执行时间超过 timeout, 则跳出while循环
- 如果所有结果都完成, 则跳出while循环
- 只将有数据的对象返回
- 每一个任务执行完会回调 _inc_decorate 给 self._finished + 1, 如果self._finished 数量大于等于task,则所有任务都完成。
总结
ceiometer监控任务队列框架如上所述,一个大的协程里面套了一个小的协程池。由于python协程存在自己的缺陷,为了满足并发,我们将大的协程拆开为进程,例如ceilometer-agent-compute-cpu, ceilometer-agent-compute-mem 等。
遗留问题:
如果一台宿主机上vm很多,那么再执行的时候,会大量并发调用libvirt接口,会造成libvirt部分锁的问题。从代码分析结果来看,只要ceilometer在interval内获取到数据即可,( sleep 时间是 interval - 函数执行时间)。
那么针对这个问题,我觉得可以限制ceilometer小协程池的数量,让获取监控数据在interval之内,来缓解libvirt锁的问题。
- ceilometer监控源码分析之任务队列
- Ceilometer项目源码分析----ceilometer项目源码结构分析
- 《转》 Ceilometer项目源码分析----ceilometer项目源码结构分析
- OkHttp3源码分析[任务队列]
- OkHttp3源码分析[任务队列]
- ceilometer polling agents源码分析
- OpenStack监控组件---Ceilometer alarm属性分析
- Ceilometer项目源码分析----ceilometer报警器服务的实现概览
- Ceilometer项目源码分析----ceilometer报警器状态评估方式之联合报警器状态评估的具体实现
- Ceilometer项目源码分析----ceilometer报警器状态评估方式之单一报警器状态评估的具体实现
- 浓墨重彩之OpenStack-12-ceilometer监控服务
- Ceilometer 分析
- Openstack之ceilometer简介及概念分析
- Ceilometer项目源码分析----ceilometer分布式报警系统的具体实现(1)
- Ceilometer项目源码分析----ceilometer分布式报警系统的具体实现(2)
- Ceilometer项目源码分析----ceilometer-alarm-notifier服务的初始化和启动
- Ceilometer项目源码分析----ceilometer-alarm-evaluator服务的初始化和启动
- Ceilometer项目源码分析----ceilometer-agent-central服务的初始化和启动
- 梯度下降法(一)入门
- 7、Eclipse下的Java反编译插件,查看源代码不再困难
- 动手写自己的cuda遇到的问题1
- Fragment跳转问题
- web项目jpush配置
- ceilometer监控源码分析之任务队列
- extjs的Ext.define()函数的用法以及注意点。
- 「视频直播技术详解」系列之四:推流和传输
- android之Broadcast Receiver详解
- 堆&优先级队列
- java多线程读取多个文件 导入数据库
- 一点思考-遇见开复
- 如何把React Native嵌入到原生android应用中
- 可视化编程 Tips 之"无需代码设置圆角" "简单处理让我们可以无需代码设置边框颜色"