openstack周期性任务分析

来源:互联网 发布:网络名称大全 编辑:程序博客网 时间:2024/05/01 05:01
在openstack中,会有一些周期性运行的任务,比如定时统计节点的状态,定时解除fixed ip的绑定等等,
这些任务是在服务的一开始就启动的,启动方式参见服务的启动函数:
   
#Service.pyclass Service(object):    def start(self):        #这部分为定期上报该服务的状态到DB中        if self.report_interval:            pulse = utils.LoopingCall(self.report_state)  #LoopingCall为实际完成周期执行工作的类            pulse.start(interval=self.report_interval,                        initial_delay=self.report_interval)            self.timers.append(pulse)        #这部分则是定期执行该服务里定义的一些periodic_task        if self.periodic_interval:            if self.periodic_fuzzy_delay:                initial_delay = random.randint(0, self.periodic_fuzzy_delay)            else:                initial_delay = None            periodic = utils.LoopingCall(self.periodic_tasks)            periodic.start(interval=self.periodic_interval,                           initial_delay=initial_delay)            self.timers.append(periodic)

   
这些periodic_task是什么呢?
 
    def periodic_tasks(self, raise_on_error=False):        """Tasks to be run at a periodic interval."""        ctxt = context.get_admin_context()        self.manager.periodic_tasks(ctxt, raise_on_error=raise_on_error)   


从这里得知是在manager中定义的,转到nova/manager.py
 
class Manager(base.Base):    __metaclass__ = ManagerMeta    def periodic_tasks(self, context, raise_on_error=False):        """Tasks to be run at a periodic interval."""        for task_name, task in self._periodic_tasks: #self._periodic_tasks这个list中就存储了需要周期执行的任务列表            full_task_name = '.'.join([self.__class__.__name__, task_name])  #某个周期执行的task任务            ticks_to_skip = self._ticks_to_skip[task_name]   #该任务的周期,如果值为N,那么间隔执行时间就为N * (基本周期)            if ticks_to_skip > 0:  #每次循环递减间隔次数,减为0时开始执行                self._ticks_to_skip[task_name] -= 1                continue            self._ticks_to_skip[task_name] = task._ticks_between_runs #重置间隔次数            try:                task(self, context)                # NOTE(tiantian): After finished a task, allow manager to                # do other work (report_state, processing AMPQ request etc.)                eventlet.sleep(0)            except Exception as e:                raise

    
问题又来了,存储了所有周期任务的self._periodic_tasks是怎么生成的呢?
我们看到Manager类的定义中有这样一句,__metaclass__ = ManagerMeta,这句的意思是指定本类的元类为ManagerMeta,
元类是用来创建类对象使用的,功能很丰富,不详细说明,这里只需要明白一点,在创建Manager类或者根据Manager类派生
子类时,会首先调用其元类–ManagarMeta的__init__方法,
 
class ManagerMeta(type):    def __init__(cls, names, bases, dict_):        """Metaclass that allows us to collect decorated periodic tasks."""        super(ManagerMeta, cls).__init__(names, bases, dict_)        try:            cls._periodic_tasks = cls._periodic_tasks[:]  #cls._periodic_tasks 为类成员变量,被所有的派生类共享        except AttributeError:            cls._periodic_tasks = []        try:            cls._ticks_to_skip = cls._ticks_to_skip.copy()        except AttributeError:            cls._ticks_to_skip = {}           for value in cls.__dict__.values():              if getattr(value, '_periodic_task', False):  #当判断某个派生子类的方法的_periodic_task属性为True时,这个方法即为周期性任务,随即加入到_periodic_tasks 中                task = value                name = task.__name__                cls._periodic_tasks.append((name, task))                cls._ticks_to_skip[name] = task._ticks_between_runs  


那么如何指定某个方法为周期性任务呢?manager.py中定义了这样一个decorator:
def periodic_task(*args, **kwargs):    def decorator(f):        f._periodic_task = True        f._ticks_between_runs = kwargs.pop('ticks_between_runs', 0)        return f    if kwargs:        return decorator    else:        return decorator(args[0])    

这个decorator完成的功能就是为被修饰的方法增加两个属性,_periodic_task和_ticks_between_runs ,
因此所有继承Manager类的并使用@periodic_task 装饰器的类方法都会被加入到_periodic_tasks 中,最终被周期执行
    
现在有哪些周期性任务?
1.  定期上报服务的状态
    
def report_state(self):        """Update the state of this service in the datastore."""        ctxt = context.get_admin_context()        zone = FLAGS.node_availability_zone        state_catalog = {}        try:            try:                service_ref = db.service_get(ctxt, self.service_id)            except exception.NotFound:                LOG.debug(_('The service database object disappeared, ''Recreating it.'))                self._create_service_ref(ctxt)                service_ref = db.service_get(ctxt, self.service_id)            state_catalog['report_count'] = service_ref['report_count'] + 1            if zone != service_ref['availability_zone']:                state_catalog['availability_zone'] = zone            db.service_update(ctxt, self.service_id, state_catalog)            if getattr(self, 'model_disconnected', False):                self.model_disconnected = False        except Exception:  # pylint: disable=W0702            if not getattr(self, 'model_disconnected', False):                self.model_disconnected = True

2.  定时获取计算节点的cpu,memory,disk等信息并上传给scheduler模块
    def _publish_service_capabilities(self, context):        """Pass data back to the scheduler at a periodic interval."""        if self.last_capabilities:            LOG.debug(_('Notifying Schedulers of capabilities ...'))            self.scheduler_rpcapi.update_service_capabilities(context,                    self.service_name, self.host, self.last_capabilities)

3.  定期解除fixed ip绑定
  @manager.periodic_task    def _disassociate_stale_fixed_ips(self, context):        if self.timeout_fixed_ips:            now = timeutils.utcnow()            timeout = FLAGS.fixed_ip_disassociate_timeout            time = now - datetime.timedelta(seconds=timeout)            num = self.db.fixed_ip_disassociate_all_by_timeout(context,                                                               self.host,                                                               time)            if num:                LOG.debug(_('Disassociated %s stale fixed ip(s)'), num)

等等等等
0 0