qianye1001 opened a new issue, #1340:
URL: https://github.com/apache/rocketmq-clients/issues/1340

   ### Before Creating the Issue
   
   - [x] I have searched the existing issues and did not find a matching open 
issue.
   
   ### Programming Language
   
   Java
   
   ### Version
   
   Current `master`
   
   ### What happened
   
   The Java gRPC PushConsumer divides its total message-count and byte cache 
limits across all assigned `ProcessQueue` instances:
   
   ```text
   per-queue count threshold = maxCacheMessageCount / processQueueCount
   per-queue byte threshold  = maxCacheMessageSizeInBytes / processQueueCount
   ```
   
   When a client is assigned many queues, each queue can therefore receive only 
a small cache quota. Once either quota is full, 
`ProcessQueueImpl.receiveMessage` schedules the next receive attempt after a 
fixed one-second delay.
   
   ACK/NACK completion removes messages from the local cache, but cache 
eviction does not wake the paused receive loop. Even if consumption drains the 
queue almost immediately, that queue still waits for the one-second timer.
   
   With server-side backlog, each receive can return immediately, so the client 
may repeatedly enter this cycle:
   
   ```text
   many assigned queues
     -> small per-queue quota
     -> cache full
     -> fixed one-second receive gap
     -> lower receive throughput
     -> consumer lag grows
     -> subsequent receives fill the cache immediately
   ```
   
   This can make receive request frequency and consumption throughput fall 
while lag continues to grow.
   
   Issue #1196 proposed a per-queue cache option. PR #1214 increased the 
default total message cache from 1024 to 4096, which mitigates the frequency of 
cache-full events but does not remove the fixed recovery gap.
   
   ### Expected behavior
   
   A cache-full queue should remain paused while it is near the high watermark, 
but should resume promptly after ACK/NACK completion drains both cache 
dimensions to a low watermark. The existing one-second task should remain only 
as a fallback.
   
   ### Proposed fix
   
   - Represent each cache-full pause with a distinct token that retains the 
not-yet-sent receive `attemptId`.
   - Store the active token in an `AtomicReference`.
   - After cache eviction, resume when both cached message count and cached 
bytes are at or below 20% of their current per-queue thresholds (`threshold / 
5L`; naturally zero for thresholds below five).
   - Use token-identity CAS so concurrent ACKs and the fallback timer can 
schedule only one resume, and a stale timer cannot affect a newer pause (ABA).
   - Resume through the consumer scheduler and reuse the paused attempt's 
`attemptId`.
   - Do not resume a dropped queue or a stopped consumer.
   - Keep the existing one-second timer as a liveness fallback.
   
   ### Scope
   
   This issue concerns the Java gRPC `PushConsumer` / `ProcessQueueImpl` 
receive loop. `SimpleConsumer` uses a separate receive path and is not affected 
by this change.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to