[openstack-dev] [ceilometer] The periodic task on openstack

Russell Bryant rbryant at redhat.com
Fri Nov 16 14:43:50 UTC 2012


On 11/16/2012 09:32 AM, Eoghan Glynn wrote:
> 
> 
>>>>> A follow-up for your discussion on IRC last night, I had a quick
>>>>> check of the loopingcall implementation, and seems there is
>>>>> really
>>>>> no time gurantee. Even if we adjust the interval for
>>>>> greenthread.sleep() dynamically, we also must make the metering
>>>>> periodic task always at the head.
>>>>>
>>>>> I think we can enhance the periodic task to meet partially our
>>>>> requirement, like create a separated task type as high-priority,
>>>>> which should make sure no long-delay.
>>>>>
>>>>> The only concern is, can we make sure the LoopingCall itself will
>>>>> be invoked on time after the greenthread.sleep(interval),
>>>>> considering the attribute of greenthread, or even python thread.
>>>>>
>>>>> openstack/common/loopingcall.py-> LoopingCall(object):
>>>>>
>>>>>                 while self._running:
>>>>>                     self.f(*self.args, **self.kw)
>>>>>                     if not self._running:
>>>>>                         break
>>>>>                     greenthread.sleep(interval)
>>>
>>> Thanks for following this up!
>>>
>>> So can I confirm that I've understood the basic issues here are
>>> that:
>>>
>>>  (a) The time spent executing tasks is not accounted for when
>>>      determining how much time to sleep between task runs. So
>>>      for example if periodic_interval is set to N seconds, the
>>>      actual time between tasks is of the order of:
>>>
>>>        N + \Sigma duration(task_i)/(1 + ticks for task_i)
>>>
>>>      The more tasks with ticks=0, and the longer the task
>>>      duration, the more we skew away from tasks executing on
>>>      wall-clock boundaries.
>>>
>>>  (b) There is no guarantee (beyond convention) that a task won't
>>>      take longer than periodic_interval/|tasks| to execute.
>>>
>>>  (c) There is an indeterminate lag after the expiry of the sleep
>>>      interval before the LoopingCall thread is re-scheduled.
>>>
>>> So could we at least address issue (a) by simply subtracting
>>> the duration of the last tasks run from the next sleep interval?
>>>
>>> e.g. change LoopingCall.start()._inner() as follows:
>>>
>>>     while self._running:
>>> +       start = datetime.datetime.now()
>>>         self.f(*self.args, **self.kw)
>>> +       end = datetime.datetime.now()
>>> +       delta = end - start
>>> +       elapsed = delta.seconds + delta.microseconds/(10 ** 6)
>>> +       delay = interval - elapsed
>>>         if not self._running:
>>>             break
>>> -       greenthread.sleep(interval)
>>> +       greenthread.sleep(delay if delay > 0 else 0)
>>>
>>> I guess that's what you meant by adjusting the interval
>>> dynamically?
>>
>>> But I'm not sure that we can always address (b) or (c) even with a
>>> special thread for high-priority/time-sensitive tasks.
>>
>> I've noticed that too.  The default interval is 60 seconds.
>> However, on a system in a lab environment I saw the tasks taking
>> 15-20 seconds.  I imagine that on more heavily loaded systems with a
>> lot of instances, it seems likely that (b) could occur.
>>
>> We could do what you're suggesting, but also parallelize the tasks
>> using a threadpool (of real threads) and only kick off a task if it
>> has finished running from its last scheduled run.  Does that seem
>> reasonable?
> 
> Yeah, that could certainly improve matters (similarly with jd_'s
> earlier suggestion).
> 
> However, here's a concern (that may derive from my ignorance of
> green versus real threads) ... if we use a pool of real threads,
> would this be problematic when a task touches codepaths previously
> monkey-patched to do the cooperative yielding required of potentially
> blocking code in order to be eventlet-friendly?
> 
> Its almost as if we'd want the standard libs to be unmonkey-patched
> when executing on real threads so as to avoid needlessly yielding and
> hence chewing up more elapsed time to task completion (if that makes
> any sense ...).

That's a good question.  Eventlet provides a threadpool implementation
that we could use for this, so if going that route I think it's all good.

http://eventlet.net/doc/threading.html#tpool-simple-thread-pool

-- 
Russell Bryant



More information about the OpenStack-dev mailing list