[ 
https://issues.apache.org/jira/browse/HDFS-17976?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18111766#comment-18111766
 ] 

ASF GitHub Bot commented on HDFS-17976:
---------------------------------------

rdhabalia opened a new pull request, #8718:
URL: https://github.com/apache/hadoop/pull/8718

   ### Description of PR
   
   A block written to a DataNode remains active until the client sends the final
   packet and the block is finalized.
   
   When a client crashes, loses network connectivity, or hangs before sending 
the
   last packet, the DataNode transfer thread can remain blocked indefinitely 
while
   waiting for input. Over time, these stalled transfers can accumulate and 
cause:
   
   - Transfer-thread starvation
   - Resource leakage
   - Degraded DataNode responsiveness
   
   Today, there is no built-in inactivity detection to reclaim resources from
   stalled transfers. The system relies on client behavior or eventual lease
   recovery, which may occur long after the actual failure.
   
   ## Solution
   
   Introduce a configurable, inactivity-based timeout for block transfers on the
   DataNode.
   
   When enabled, the DataNode tracks packet-arrival activity for each ongoing
   block write using a monotonic clock. A single scheduled check per transfer
   runs every `timeout / 2` and compares the time since the last received packet
   against `timeout / 2`.
   
   ### Transfer Activity Detection
   
   - If a packet arrived within `timeout / 2`:
     - The stream is considered active.
     - The check is rescheduled.
     - This provides an automatic reset for healthy streams.
   
   - Otherwise:
     - The transfer is considered stalled.
     - The transfer is aborted.
   
   Polling every `timeout / 2` bounds the detection latency to between
   `timeout / 2` and `timeout` after the client stops sending.
   
   ### Safe Transfer Abort
   
   The abort runs on the shared scheduler thread and deliberately performs **no
   disk I/O**.
   
   The on-disk streams (`out` / `checksumOut`) are written by the receive thread
   **without holding the `BlockReceiver` monitor**. Flushing these streams from
   the scheduler thread could race with those writes and potentially corrupt the
   replica.
   
   Instead, the scheduler:
   
   1. Closes only the client input stream.
   2. This unblocks the receive thread's blocked socket read.
   3. The receive thread unwinds and performs its own single-threaded cleanup.
   
   Data already acknowledged to the client is already durable on disk. The
   replica remains in the **RBW (Replica Being Written)** state, allowing the
   NameNode's existing lease-recovery / block-synchronization path to finalize
   the block without data loss.
   
   ## Scheduler Design
   
   The timeout checks use a shared `ScheduledThreadPoolExecutor` with **2 daemon
   threads**.
   
   The scheduler:
   
   - Is created lazily at DataNode startup only when the timeout is configured.
   - Adds **zero threads and zero overhead when the feature is disabled**.
   - Uses `remove-on-cancel` so per-block checks cancelled when a transfer
     completes do not accumulate in the delay queue.
   - Does not execute delayed tasks after shutdown.
   
   The last-packet timestamp is updated only when the timeout feature is 
enabled,
   avoiding unnecessary atomic writes on the hot path when the feature is
   disabled.
   
   ## Client Socket Timeout Considerations
   
   Because a stall is declared after no packet is received for `timeout / 2`,
   the DataNode timeout must be configured comfortably larger than the client
   socket read timeout.
   
   A healthy idle `hflush` / `hsync` stream still sends heartbeat packets 
roughly
   every half of the socket timeout.
   
   The DataNode logs a warning if the configured transfer timeout is not
   sufficiently larger than the client socket timeout.
   
   ## Configuration
   
   | Configuration | Default | Description |
   |---|---:|---|
   | `dfs.datanode.last.packet.receive.timeout.ms` | `0` | Last-packet 
inactivity timeout in milliseconds. `0` disables the feature. |
   
   A typical enabled value is:
   
   ```text
   dfs.datanode.last.packet.receive.timeout.ms=600000
   ````
   
   This corresponds to a **10-minute timeout**.
   
   The change is fully backward compatible and disabled by default.
   
   ## Testing
   
   ### `TestBlockReceiverLastPacketTimeout`
   
   Verifies the DataNode-side scheduler wiring:
   
   * The shared scheduler is created only when the timeout is enabled.
   * `remove-on-cancel` is configured correctly.
   * Delayed tasks do not execute after scheduler shutdown.
   
   ### `TestBlockReceiverTransferTimeout`
   
   Runs an end-to-end test using `MiniDFSCluster` and verifies that a genuinely
   stuck client is deterministically aborted.
   
   The test uses a single DataNode with DataNode replacement disabled so that a
   broken pipeline cannot be silently recovered.
   
   It also verifies that healthy streams are never falsely aborted, including:
   
   * Full transfers
   * Slow-but-steady writers
   * Writers whose packet gaps remain just below the timeout threshold, even
     when the total transfer time exceeds the timeout
   * Disabled timeout configuration
   * Multiple concurrent transfers
   
   
   
   ### How was this patch tested?
   Tested by newly added unit test
   
   
   ### For code changes:
   
   - [ ] Does the title of this PR start with the corresponding JIRA issue id 
(e.g. 'HADOOP-17799. Your PR title ...')?
   - [ ] Object storage: Have the integration tests been executed and the 
endpoint
         declared according to the connector-specific documentation? *Note: 
Automated CI
         testing doesn't cover all cases so manual testing with cloud storage 
is still
         required.*
   - [ ] If adding new dependencies to the code, are these dependencies 
licensed in a way that is compatible for inclusion under [ASF 
2.0](http://www.apache.org/legal/resolved.html#category-a)?
   - [ ] If applicable, have you updated the `LICENSE`, `LICENSE-binary`, 
`NOTICE-binary` files?
   
   ### AI Tooling
   
   If an AI tool was used:
   
   - [ ] The PR includes the phrase "Contains content generated by <tool>"
         where <tool> is the name of the AI tool used.
   - [ ] My use of AI contributions follows the ASF legal policy
         https://www.apache.org/legal/generative-tooling.html
   
   




> HDFS DataNode add configurable inactivity-based timeout for DataNode block 
> transfers
> ------------------------------------------------------------------------------------
>
>                 Key: HDFS-17976
>                 URL: https://issues.apache.org/jira/browse/HDFS-17976
>             Project: Hadoop HDFS
>          Issue Type: Improvement
>          Components: hdfs
>            Reporter: Rajan Dhabalia
>            Priority: Major
>
> h2. Summary
> Add a configurable inactivity-based timeout to safely terminate stalled 
> DataNode block transfers, reclaim resources, and preserve partially written 
> replicas for recovery.
> h2. Issue Type
> Improvement
> h2. Component/s
> datanode
> h2. Description
> h3. Motivation
> A block write remains active until the client sends the final packet and the 
> block is finalized. If a client crashes, loses connectivity, or becomes 
> unresponsive, the DataNode transfer thread can remain blocked waiting for 
> additional data.
> Stalled transfers can accumulate over time, consuming transfer threads and 
> other resources and potentially affecting healthy client operations.
> h3. Approach
> Introduce a configurable inactivity timeout for DataNode block transfers.
> When enabled:
>  * Track packet-arrival activity for each ongoing block write.
>  * Schedule an inactivity check for each active transfer.
>  * Terminate the transfer if no packet is received within the configured 
> timeout.
>  * Flush buffered data before termination.
>  * Close the input stream to interrupt blocked reads.
>  * Keep the replica in *RBW (Replica Being Written)* state.
>  * Allow existing NameNode lease recovery and block synchronization to 
> recover and finalize the replica.
> The timeout uses a shared `ScheduledExecutorService` and is created lazily 
> only when enabled. When disabled, there are no additional scheduler threads 
> or timeout processing.
> h3. Configuration
> ||Property||Default||Description||
> |`dfs.datanode.last.packet.receive.timeout.ms`|0|Inactivity timeout for an 
> ongoing block transfer. If no packet is received within the configured 
> window, the transfer is considered stalled and terminated. `0` or negative 
> disables the feature.|
> h3. Transfer Lifecycle
> {code:java}
> Client starts block write
>         |
>         v
> DataNode receives packets
>         |
>         v
> Track packet activity
>         |
>         v
> Packet received?
>    /            \
>  Yes             No
>   |               |
>   v               v
> Reset timer    Timeout reached
>                   |
>                   v
>           Flush buffered data
>                   |
>                   v
>           Close input stream
>                   |
>                   v
>           Replica remains RBW
>                   |
>                   v
>        Existing lease recovery /
>        block synchronization
>                   |
>                   v
>             Block finalized
> {code}
> h3. Data Safety
> When a stalled transfer is terminated:
>  # Buffered data is flushed.
>  # The input stream is closed.
>  # The replica remains in RBW state.
>  # Existing HDFS recovery mechanisms handle subsequent recovery/finalization.
> This preserves data already received by the DataNode while reclaiming stalled 
> transfer resources.
> h3. Results
> The inactivity timeout provides:
>  * Bounded resource usage for stalled transfers.
>  * Prevention of indefinite transfer-thread retention after client failures.
>  * Reduced risk of transfer-thread exhaustion during client failure bursts.
>  * Preservation of partially written replica data.
>  * Compatibility with existing HDFS recovery mechanisms.
>  * No additional overhead when disabled.
> h3. Estimated Impact
> This is primarily a reliability and resource-reclamation improvement rather 
> than a throughput optimization.
> ||Dimension||Without Timeout||With Inactivity Timeout||
> |Stalled transfer lifetime|Potentially unbounded|Bounded by configured 
> timeout|
> |Transfer threads|Can accumulate|Reclaimed after inactivity|
> |Client failure bursts|Risk of resource exhaustion|Resource usage remains 
> bounded|
> |Partially written data|Preserved through existing recovery|Preserved; 
> replica remains RBW|
> |Normal transfers|Existing behavior|Unchanged|
> |Disabled overhead|Existing behavior|No additional scheduler/timeout 
> processing|
> h3. Operational Considerations
> The timeout should be configured based on workload characteristics. An overly 
> aggressive timeout could terminate legitimately slow transfers, while a 
> sufficiently large timeout allows temporary network or client stalls while 
> still reclaiming resources from genuinely stalled transfers.
> The feature is therefore *disabled by default* and can be enabled explicitly 
> by operators.
> h2. Expected Impact
>  * Improve DataNode resilience to crashed, disconnected, or hung clients.
>  * Prevent stalled transfers from holding resources indefinitely.
>  * Bound transfer-resource usage during client failure bursts.
>  * Preserve partially written data for existing recovery mechanisms.
>  * Keep normal block-transfer behavior unchanged when disabled.
> h2. Backward Compatibility
> The feature is {*}disabled by default{*}. Existing DataNode block-transfer 
> behavior remains unchanged unless 
> `dfs.datanode.last.packet.receive.timeout.ms` is explicitly configured.



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

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to