Stefan Egli created OAK-2587:
--------------------------------
Summary: observation processing too eager/unfair under load
Key: OAK-2587
URL: https://issues.apache.org/jira/browse/OAK-2587
Project: Jackrabbit Oak
Issue Type: Bug
Components: core
Affects Versions: 1.0.12
Reporter: Stefan Egli
Priority: Critical
The current implementation of oak's observation event processing is too eager
and thus unfair under load scenarios.
Consider having many (eg 200) Eventlisteners but only a relatively small
threadpool (eg 5 as is the default in sling) backing them. When processing
changes for a particular BackgroundObserver, that one (in
BackgroundObserver.completionHandler.call) currently processes *all changes
irrespective of how many there are* - ie it is *eager*. Only once that
BackgroundObserver processed all changes will it let go and 'pass the thread'
to the next BackgroundObserver. Now if for some reason changes (ie commits) are
coming in while a BackgroundObserver is busy processing an earlier change, this
will lengthen that while loop. As a result the remaining (eg 195)
*EventListeners will have to wait for a potentially long time* until it's their
turn - thus *unfair*.
Now combine the above pattern with a scenario where mongo is used as the
underlying store. In that case in order to remain highly performant it is
important that the diffs (for compareAgainstBaseState) are served from the
MongoDiffCache for as many cases as possible to avoid doing a round-trip to
mongoD. The unfairness in the BackgroundObservers can now result in a large
delay between the 'first' observers getting the event and the 'last' one (of
those 200). When this delay increases due to a burst in the load, there is a
risk of the diffs to no longer be in the cache - those last observers are
basically kicked out of the (diff) cache. Once this happens, *the situation
gets even worse*, since now you have yet new commits coming in and old changes
still having to be processed - all of which are being processed through in
'stripes of 5 listeners' before the next one gets a chance. This at some point
results in a totally inefficient cache behavior, or in other words, at some
point all diffs have to be read from mongoD.
To avoid this there are probably a number of options - a few one that come to
mind:
* increase thread-pool to match or be closer to the number of listeners (but
this has other disadvantages, eg cost of thread-switching)
* make BackgroundObservers fairer by limiting the number of changes they
process before they give others a chance to be served by the pool.
--
This message was sent by Atlassian JIRA
(v6.3.4#6332)