[
https://issues.apache.org/jira/browse/HADOOP-19918?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
erzhen wu updated HADOOP-19918:
-------------------------------
Description:
h2. Problem Description
When `rpc.metrics.quantile.enable=true` is enabled in production
NameNode,
we observed severe lock contention causing all IPC Handler threads to become
BLOCKED on `MutableQuantiles.add()`, resulting in:
* *RpcQueueTimeAvgTime increases significantly* : Requests queuing in
CallQueue longer
* *CallQueueLength increases dramatically* :More requests waiting to be
processed
* NameNode RPC throughput degradation:Handler threads blocked on metrics
update
h2. Thread Dump Analysis
From production NameNode jstack, we found 247 IPC Handler threads BLOCKED
waiting on the same `MutableQuantiles` monitor lock:
{code:java}
Thread 283 (IPC Server handler 191 on default port 8020):
State: BLOCKED
Blocked count: 15596
Waited count: 28409
Blocked on org.apache.hadoop.metrics2.lib.MutableQuantiles@659a2455
Blocked by 300 (IPC Server handler 208 on default port 8020)
Stack:
org.apache.hadoop.metrics2.lib.MutableQuantiles.add(MutableQuantiles.java:133)
org.apache.hadoop.ipc.metrics.RpcMetrics.addRpcQueueTime(RpcMetrics.java:245)
org.apache.hadoop.ipc.Server.updateMetrics(Server.java:587)
org.apache.hadoop.ipc.Server$Handler.run(Server.java:3008){code}
h3. Root Cause
The `synchronized` keyword on `MutableQuantiles.add()` and
`SampleQuantiles.insert()`
creates a global lock contention point:
{code:java}
public synchronized void add(long value) {
estimator.insert(value);
}
/**
* Add a new value from the stream.
*
* @param v
*/
synchronized public void insert(long v) {
buffer[bufferCount] = v;
bufferCount++;
count++;
if (bufferCount == buffer.length) {
insertBatch();
compress();
}
} {code}
Lock Contention Chain
When bufferCount == buffer.length (buffer is full), the thread holding
the lock executes insertBatch() + compress() which can take milliseconds,
during which all other Handler threads are BLOCKED:
{code:java}
Thread A (holds lock):
→ MutableQuantiles.add()
→ SampleQuantiles.insert()
→ buffer is full (500 elements)
→ insertBatch()
→ compress()
Thread B, C, D, ... (247 threads):
→ MutableQuantiles.add()
→ BLOCKED waiting for Thread A to release lock
→ Cannot process next RPC request
→ CallQueueLength increases
→ RpcQueueTimeAvgTime increases {code}
h3. Metrics
!image-2026-06-11-18-54-43-972.png|width=580,height=247!
!image-2026-06-11-18-55-17-240.png|width=590,height=246!
h3. Impact Analysis
The blocking happens in updateMetrics() after RPC processing is
complete:
{code:java}
// Server.java - Handler.run()
void updateMetrics(Call call, long startTime, boolean connDropped) {
// ...
rpcMetrics.addRpcQueueTime(queueTime); // ← BLOCKS HERE (95% of
threads)
rpcMetrics.addRpcLockWaitTime(waitTime);
rpcMetrics.addRpcProcessingTime(processingTime);
} {code}
h3. This means:
# Handler thread completes RPC processing successfully
# Calls updateMetrics() to report queue time
# First call addRpcQueueTime() → BLOCKS on MutableQuantiles lock
# Handler thread cannot process next request in CallQueue
# CallQueueLength increases as new requests arrive
# RpcQueueTimeAvgTime increases as requests wait longer in queue
was:
h2. Problem Description
When `rpc.metrics.quantile.enable=true` is enabled in production
NameNode,
we observed severe lock contention causing all IPC Handler threads to become
BLOCKED on `MutableQuantiles.add()`, resulting in:
* *RpcQueueTimeAvgTime increases significantly* : Requests queuing in
CallQueue longer
* *CallQueueLength increases dramatically* :More requests waiting to be
processed
* NameNode RPC throughput degradation:Handler threads blocked on metrics
update
h2. Thread Dump Analysis
From production NameNode jstack, we found 247 IPC Handler threads BLOCKED
waiting on the same `MutableQuantiles` monitor lock:
{code:java}
Thread 283 (IPC Server handler 191 on default port 8020):
State: BLOCKED
Blocked count: 15596
Waited count: 28409
Blocked on org.apache.hadoop.metrics2.lib.MutableQuantiles@659a2455
Blocked by 300 (IPC Server handler 208 on default port 8020)
Stack:
org.apache.hadoop.metrics2.lib.MutableQuantiles.add(MutableQuantiles.java:133)
org.apache.hadoop.ipc.metrics.RpcMetrics.addRpcQueueTime(RpcMetrics.java:245)
org.apache.hadoop.ipc.Server.updateMetrics(Server.java:587)
org.apache.hadoop.ipc.Server$Handler.run(Server.java:3008){code}
h3. Root Cause
The `synchronized` keyword on `MutableQuantiles.add()` and
`SampleQuantiles.insert()`
creates a global lock contention point:
{code:java}
public synchronized void add(long value) {
estimator.insert(value);
}
/**
* Add a new value from the stream.
*
* @param v
*/
synchronized public void insert(long v) {
buffer[bufferCount] = v;
bufferCount++;
count++;
if (bufferCount == buffer.length) {
insertBatch();
compress();
}
} {code}
Lock Contention Chain
When bufferCount == buffer.length (buffer is full), the thread holding
the lock executes insertBatch() + compress() which can take milliseconds,
during which all other Handler threads are BLOCKED:
{code:java}
Thread A (holds lock):
→ MutableQuantiles.add()
→ SampleQuantiles.insert()
→ buffer is full (500 elements)
→ insertBatch()
→ compress()
Thread B, C, D, ... (247 threads):
→ MutableQuantiles.add()
→ BLOCKED waiting for Thread A to release lock
→ Cannot process next RPC request
→ CallQueueLength increases
→ RpcQueueTimeAvgTime increases {code}
h3. Metrics
!image-2026-06-11-18-54-43-972.png|width=580,height=247!
!image-2026-06-11-18-55-17-240.png|width=590,height=246!
h3. Impact Analysis
The blocking happens in updateMetrics() after RPC processing is
complete:
{code:java}
// Server.java - Handler.run()
void updateMetrics(Call call, long startTime, boolean connDropped) {
// ...
rpcMetrics.addRpcQueueTime(queueTime); // ← BLOCKS HERE (95% of
threads)
rpcMetrics.addRpcLockWaitTime(waitTime);
rpcMetrics.addRpcProcessingTime(processingTime);
} {code}
h3. This means:
# Handler thread completes RPC processing successfully
# Calls updateMetrics() to report queue time
# First call addRpcQueueTime() → BLOCKS on MutableQuantiles lock
# Handler thread cannot process next request in CallQueue
# CallQueueLength increases as new requests arrive
# RpcQueueTimeAvgTime increases as requests wait longer in queue
> MutableQuantiles.add() causes severe lock contention, blocking all IPC
> Handler threads and degrading RPC performance
> --------------------------------------------------------------------------------------------------------------------
>
> Key: HADOOP-19918
> URL: https://issues.apache.org/jira/browse/HADOOP-19918
> Project: Hadoop Common
> Issue Type: Bug
> Components: hadoop-common, metrics
> Affects Versions: 3.3.3
> Reporter: erzhen wu
> Priority: Major
> Attachments: image-2026-06-11-18-43-36-472.png,
> image-2026-06-11-18-54-43-972.png, image-2026-06-11-18-55-17-240.png
>
>
> h2. Problem Description
> When `rpc.metrics.quantile.enable=true` is enabled in production
> NameNode,
> we observed severe lock contention causing all IPC Handler threads to become
> BLOCKED on `MutableQuantiles.add()`, resulting in:
> * *RpcQueueTimeAvgTime increases significantly* : Requests queuing in
> CallQueue longer
> * *CallQueueLength increases dramatically* :More requests waiting to be
> processed
> * NameNode RPC throughput degradation:Handler threads blocked on metrics
> update
>
> h2. Thread Dump Analysis
> From production NameNode jstack, we found 247 IPC Handler threads
> BLOCKED
> waiting on the same `MutableQuantiles` monitor lock:
> {code:java}
> Thread 283 (IPC Server handler 191 on default port 8020):
> State: BLOCKED
> Blocked count: 15596
> Waited count: 28409
> Blocked on org.apache.hadoop.metrics2.lib.MutableQuantiles@659a2455
> Blocked by 300 (IPC Server handler 208 on default port 8020)
> Stack:
> org.apache.hadoop.metrics2.lib.MutableQuantiles.add(MutableQuantiles.java:133)
>
> org.apache.hadoop.ipc.metrics.RpcMetrics.addRpcQueueTime(RpcMetrics.java:245)
> org.apache.hadoop.ipc.Server.updateMetrics(Server.java:587)
> org.apache.hadoop.ipc.Server$Handler.run(Server.java:3008){code}
> h3. Root Cause
> The `synchronized` keyword on `MutableQuantiles.add()` and
> `SampleQuantiles.insert()`
> creates a global lock contention point:
> {code:java}
> public synchronized void add(long value) {
> estimator.insert(value);
> }
> /**
> * Add a new value from the stream.
> *
> * @param v
> */
> synchronized public void insert(long v) {
> buffer[bufferCount] = v;
> bufferCount++;
> count++;
> if (bufferCount == buffer.length) {
> insertBatch();
> compress();
> }
> } {code}
>
> Lock Contention Chain
> When bufferCount == buffer.length (buffer is full), the thread holding
> the lock executes insertBatch() + compress() which can take milliseconds,
> during which all other Handler threads are BLOCKED:
> {code:java}
> Thread A (holds lock):
> → MutableQuantiles.add()
> → SampleQuantiles.insert()
> → buffer is full (500 elements)
> → insertBatch()
> → compress()
> Thread B, C, D, ... (247 threads):
> → MutableQuantiles.add()
> → BLOCKED waiting for Thread A to release lock
> → Cannot process next RPC request
> → CallQueueLength increases
> → RpcQueueTimeAvgTime increases {code}
> h3. Metrics
> !image-2026-06-11-18-54-43-972.png|width=580,height=247!
> !image-2026-06-11-18-55-17-240.png|width=590,height=246!
> h3. Impact Analysis
>
> The blocking happens in updateMetrics() after RPC processing is
> complete:
> {code:java}
> // Server.java - Handler.run()
>
> void updateMetrics(Call call, long startTime, boolean connDropped) {
> // ...
>
> rpcMetrics.addRpcQueueTime(queueTime); // ← BLOCKS HERE (95% of
> threads)
> rpcMetrics.addRpcLockWaitTime(waitTime);
> rpcMetrics.addRpcProcessingTime(processingTime);
> } {code}
>
> h3. This means:
> # Handler thread completes RPC processing successfully
> # Calls updateMetrics() to report queue time
> # First call addRpcQueueTime() → BLOCKS on MutableQuantiles lock
> # Handler thread cannot process next request in CallQueue
> # CallQueueLength increases as new requests arrive
> # RpcQueueTimeAvgTime increases as requests wait longer in queue
>
>
>
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]