[ 
https://issues.apache.org/jira/browse/IGNITE-28955?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Anton Vinogradov updated IGNITE-28955:
--------------------------------------
    Description: 
h3. What happens

A continuous query subscriber can be flooded with notifications. Nothing slows 
the sender down: {{messageQueueLimit}} is 0 by default 
({{TcpCommunicationSpi.DFLT_MSG_QUEUE_LIMIT}} = 
{{GridNioServer.DFLT_SEND_QUEUE_LIMIT}}), which means unlimited. The server 
sends a notification as soon as it creates one, and a subscriber that cannot 
keep up only accumulates them on the heap.

h3. How it shows up

*{{CacheContinuousQueryConcurrentPartitionUpdateTest}}#concurrentUpdatesAndQueryStart*
 runs 10 threads that update 3 caches in a loop until the listener has counted 
enough events. With ZooKeeper discovery the client falls behind. One run on 12 
cores and a 9.6G heap:
* the client received 15 534 790 messages (2.27 GB) in about 170 seconds;
* the pause detector logged 131 long JVM pauses, the longest 3.7 s;
* the client lost its ZooKeeper session and the coordinator evicted it.

With a smaller heap the same load ends in {{OutOfMemoryError}}, with millions 
of retained *{{GridContinuousMessage}}* and *{{CacheContinuousQueryEntry}}* — 
see the heap dump in IGNITE-28673. Both endings are the same overload.

h3. Why it matters beyond this test

IGNITE-28673 moves the completion of a continuous routine start off discovery 
and onto the communication path, where it shares one connection with the 
notifications ({{connectionsPerNode}} is 1 by default). Under this overload the 
start result waits behind them. While the subscriber can be flooded, a fix 
there that only changes message priority cannot be verified: the subscriber 
dies before ordering starts to matter.

h3. Open question

Ignite already has {{slowClientQueueLimit}} for subscribers that cannot keep 
up, but it is off by default 
({{TcpCommunicationConfiguration#slowClientQueueLimit}} is 0). Whether the 
answer is a different default, back pressure inside the continuous query path, 
or both, needs a decision.


  was:
Starting a continuous query can hang for minutes on a cluster that uses 
ZooKeeper discovery while the same caches are under a heavy update load.

h3. Reproduction

Add a subclass of {{CacheContinuousQueryConcurrentPartitionUpdateTest}} that 
runs under ZooKeeper discovery (the patch attached to IGNITE-28673 does exactly 
that) and run {{testConcurrentUpdatesAndQueryStartAtomicCacheGroup}}.

On current master it does not finish: 318 s against the 300 s test timeout. TCP 
discovery is not affected - the same test class passes in 45 s.

h3. Root cause

The message that completes the routine start and the continuous query 
notifications share a topic and a pool:

{code:java}
// GridContinuousProcessor, sending the start result
ctx.io().sendToGridTopic(node, TOPIC_CONTINUOUS, new 
ContinuousRoutineStartResultMessage(...), SYSTEM_POOL);

// GridContinuousProcessor, sending CQ notifications
ctx.io().sendToGridTopic(node, TOPIC_CONTINUOUS, msg, SYSTEM_POOL, ackC);
{code}

Under a heavy update load the notifications fill the queue, and the single 
{{ContinuousRoutineStartResultMessage}} waits behind them - head-of-line 
blocking. {{cache.query(qry)}} waits for that message, so the caller sees a 
hang. The analysis in IGNITE-28673 shows the same picture from a heap dump: 
millions of retained {{GridContinuousMessage}} and 
{{CacheContinuousQueryEntry}} objects and one waiting 
{{ContinuousRoutineStartResultMessage}}.

h3. Why only ZooKeeper today

{{GridContinuousProcessor}} picks the path by {{immutableDiscoCustomMsg = 
!ctx.discovery().mutableCustomMessages()}}, which reads the 
{{@DiscoverySpiMutableCustomMessageSupport}} annotation of the configured SPI. 
{{TcpDiscoverySpi}} has it, so the routine start is acknowledged over discovery 
and never touches the communication queue. {{ZookeeperDiscoverySpi}} does not, 
so it already uses the communication path - and hits this.

h3. Why it matters beyond ZooKeeper

IGNITE-28673 removes the mutable path and makes the communication one the only 
path. Merging it without fixing this would extend the hang to TCP discovery, 
that is, to everyone. So this blocks IGNITE-28673.


        Summary: Continuous query notifications can overload the subscriber  
(was: Continuous query start hangs under load with ZooKeeper discovery)

> Continuous query notifications can overload the subscriber
> ----------------------------------------------------------
>
>                 Key: IGNITE-28955
>                 URL: https://issues.apache.org/jira/browse/IGNITE-28955
>             Project: Ignite
>          Issue Type: Bug
>            Reporter: Anton Vinogradov
>            Priority: Major
>              Labels: ise
>             Fix For: 2.19
>
>
> h3. What happens
> A continuous query subscriber can be flooded with notifications. Nothing 
> slows the sender down: {{messageQueueLimit}} is 0 by default 
> ({{TcpCommunicationSpi.DFLT_MSG_QUEUE_LIMIT}} = 
> {{GridNioServer.DFLT_SEND_QUEUE_LIMIT}}), which means unlimited. The server 
> sends a notification as soon as it creates one, and a subscriber that cannot 
> keep up only accumulates them on the heap.
> h3. How it shows up
> *{{CacheContinuousQueryConcurrentPartitionUpdateTest}}#concurrentUpdatesAndQueryStart*
>  runs 10 threads that update 3 caches in a loop until the listener has 
> counted enough events. With ZooKeeper discovery the client falls behind. One 
> run on 12 cores and a 9.6G heap:
> * the client received 15 534 790 messages (2.27 GB) in about 170 seconds;
> * the pause detector logged 131 long JVM pauses, the longest 3.7 s;
> * the client lost its ZooKeeper session and the coordinator evicted it.
> With a smaller heap the same load ends in {{OutOfMemoryError}}, with millions 
> of retained *{{GridContinuousMessage}}* and *{{CacheContinuousQueryEntry}}* — 
> see the heap dump in IGNITE-28673. Both endings are the same overload.
> h3. Why it matters beyond this test
> IGNITE-28673 moves the completion of a continuous routine start off discovery 
> and onto the communication path, where it shares one connection with the 
> notifications ({{connectionsPerNode}} is 1 by default). Under this overload 
> the start result waits behind them. While the subscriber can be flooded, a 
> fix there that only changes message priority cannot be verified: the 
> subscriber dies before ordering starts to matter.
> h3. Open question
> Ignite already has {{slowClientQueueLimit}} for subscribers that cannot keep 
> up, but it is off by default 
> ({{TcpCommunicationConfiguration#slowClientQueueLimit}} is 0). Whether the 
> answer is a different default, back pressure inside the continuous query 
> path, or both, needs a decision.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to