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

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

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

   ### Description of PR
   
   Large sequential scans, such as analytics,  bulk copies, and
   columnar readers, open a `DFSInputStream` and read a file end-to-end.
   
   Today, each block is fetched synchronously:
   
   1. The reader thread opens a `BlockReader`.
   2. It waits for the DataNode/network round trip.
   3. It drains the block.
   4. It repeats the process for the next block.
   
   The per-block open latency and single-block-at-a-time pipeline leave the
   client CPU idle while waiting on I/O and cap throughput well below what the
   DataNodes and network can deliver.
   
   This change adds an **opt-in, client-side read-ahead prefetcher** that 
fetches
   blocks ahead of the reader's cursor using a shared background thread pool.
   By the time the reader reaches a prefetched block, the block is already
   resident in memory and can be served as an in-memory copy.
   
   ## Approach
   
   ### BlockPrefetcher
   
   - Introduces a new `BlockPrefetcher` that maintains a bounded, sliding window
     of block-sized buffers ahead of the current read position.
   - Blocks are filled in chunks using a shared, JVM-wide daemon thread pool.
   - The thread pool uses:
     - `SynchronousQueue`
     - `AbortPolicy`
   - When all workers are busy, a prefetch submission is rejected and skipped
     rather than blocking the foreground reader thread.
   
   ### DFSInputStream Integration
   
   - `DFSInputStream.read(byte[])` and `read(ByteBuffer)` first attempt to serve
     data from the prefetch cache.
   - On a cache hit:
     - The read position is advanced.
     - The stateful synchronous reader is invalidated.
     - Read statistics are updated exactly as they are on the direct path.
     - Locality is preserved across short-circuit, local, and remote reads.
   - On a cache miss:
     - The normal synchronous read path is used.
     - Block locations are cached for subsequent prefetch operations.
   
   ### Prefetch Safety and Correctness
   
   - Prefetch operates entirely using cached block locations.
   - It never issues a `getBlockLocations` RPC.
   - It does not mutate foreground retry state while a foreground read may hold
     `infoLock`.
   - The following cases are excluded for correctness:
     - Non-uniform block sizes
     - Striped (EC) files
     - Under-construction files
     - Single-block files
   
   ### Metrics and Observability
   
   - A shared, opt-in scheduled task periodically logs per-stream cache
     hit/miss ratios at `INFO` level.
   - Metrics logging occurs only when metrics logging is enabled.
   
   ### Global Memory Budget
   
   - A global byte budget bounds the total memory held by all prefetch buffers
     across the JVM.
   - The budget grows to the largest configured value across clients.
   - Memory is strictly reserved and released on a per-stream basis.
   
   ## Configuration
   
   All configuration is client-side. The feature is **disabled by default**.
   
   | Configuration | Description |
   |---|---|
   | `dfs.client.prefetch.enabled` | Enables client-side read-ahead prefetching 
|
   | `dfs.client.prefetch.size` | Per-stream read-ahead window |
   | `dfs.client.prefetch.max.bytes` | JVM-wide prefetch memory cap |
   | `dfs.client.prefetch.chunk.size` | Prefetch fill granularity |
   | `dfs.client.prefetch.threads` | Shared prefetch worker thread count |
   | `dfs.client.prefetch.threadpool.size` | Shared prefetch worker thread pool 
size |
   | `dfs.client.prefetch.ttl.ms` | Buffer time-to-live |
   | `dfs.client.prefetch.metrics.log.enabled` | Enables periodic cache 
hit-ratio logging |
   
   ## Results
   
   A single-client sequential read benchmark was run with:
   
   - **File size:** 10 GB
   - **Block size:** 512 MB
   - **Prefetch threads:** 5
   - **Prefetch window:** ~3 GB
   
   ### Performance
   
   | Metric | Result |
   |---|---:|
   | Baseline throughput | 406.8 MB/s |
   | Prefetch throughput | 1,419.5 MB/s |
   | Average improvement | **~3.49x** |
   | Peak throughput | **~1.58 GB/s** |
   | Cache hit ratio | **~81%** |
   
   The feature is **off by default** and has no impact on the read path until
   explicitly enabled.
   
   
   
   
   <!--
     Thanks for sending a pull request!
       1. If this is your first time, please read our contributor guidelines: 
https://cwiki.apache.org/confluence/display/HADOOP/How+To+Contribute
       2. Make sure your PR title starts with JIRA issue id, e.g., 
'HADOOP-17799. Your PR title ...'.
   -->
   
   
   ### 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 Client-Side Block Prefetch to Improve Large Sequential Read Throughput
> ---------------------------------------------------------------------------
>
>                 Key: HDFS-17975
>                 URL: https://issues.apache.org/jira/browse/HDFS-17975
>             Project: Hadoop HDFS
>          Issue Type: Improvement
>          Components: hdfs-client
>            Reporter: Rajan Dhabalia
>            Priority: Major
>
> h2. Summary
> Add client-side block prefetching (parallel read-ahead) to `DFSInputStream` 
> to improve throughput for large and sequential read workloads.
> h2. Issue Type
> Improvement
> h2. Component/s
> hdfs-client
> h2. Description
> h3. Motivation
> Large scan and sequential read workloads on `DFSInputStream` can be limited 
> by synchronous, one-block-at-a-time reads. The latency of each remote block 
> read can stall the consumer and prevent full utilization of available network 
> and DataNode capacity.
> Client-side prefetching hides this latency by fetching upcoming blocks in 
> parallel while the consumer processes previously read data.
> h3. Approach
> Introduce a config-gated, default-off `BlockPrefetcher` in `DFSInputStream`.
> When enabled:
>  * Asynchronously prefetch upcoming data using a bounded thread pool.
>  * Store prefetched data in a bounded in-memory cache.
>  * Serve reads directly from the cache when available.
>  * Fall back to the existing synchronous read path on cache misses.
>  * Support configurable prefetch window, chunk size, cache size, worker 
> threads, and TTL.
>  * Provide optional periodic metrics logging for cache hit ratio and 
> prefetched bytes.
>  * Add `PrefetchReadExample` and unit tests.
> The existing read path remains unchanged when prefetching is disabled.
> h3. Configuration
> ||Property||Default||Description||
> |`dfs.client.prefetch.enabled`|false|Master switch for client-side 
> prefetching|
> |`dfs.client.prefetch.size`|See docs|Prefetch window size|
> |`dfs.client.prefetch.max.bytes`|See docs|Maximum bytes held in the prefetch 
> cache|
> |`dfs.client.prefetch.chunk.size`|See docs|Size of each prefetched chunk|
> |`dfs.client.prefetch.threads`|See docs|Number of prefetch worker threads|
> |`dfs.client.prefetch.threadpool.size`|See docs|Prefetch thread-pool size|
> |`dfs.client.prefetch.ttl.ms`|See docs|TTL for cached prefetched data|
> |`dfs.client.prefetch.metrics.log.enabled`|false|Enable periodic prefetch 
> metrics logging|
> |`dfs.client.prefetch.metrics.log.interval.ms`|See docs|Metrics logging 
> interval|
> h3. Results
> Testing on large sequential read workloads showed:
>  * {*}Up to 3.49x higher average read throughput{*}, approximately {*}249% 
> improvement{*}.
>  * Peak throughput of approximately {*}1.58 GB/s{*}.
>  * Approximately {*}81% prefetch cache hit ratio{*}.
>  * Approximately *4 out of 5 reads* served from the prefetch cache.
>  * No change to the existing read path when the feature is disabled.
> h3. Estimated Improvement
> The benefit is workload-dependent and increases with read sequentiality and 
> the amount of latency that can be hidden through parallel prefetching.
> ||Workload||Expected Benefit||Rationale||
> |Large sequential scan|~3x to 3.5x|Upcoming blocks can be fetched in parallel 
> while earlier data is processed|
> |Mixed sequential + occasional seek|~1.8x to 2.5x|Sequential portions 
> benefit, while seeks reduce cache effectiveness|
> |Random / small reads|~1x|Limited sequentiality provides little opportunity 
> for prefetching|
> h3. Resource Protection
> Prefetching is bounded to prevent uncontrolled memory or CPU consumption:
>  * Maximum prefetch cache size
>  * Configurable prefetch window and chunk size
>  * Bounded worker threads and thread-pool size
>  * Entry TTL
>  * Optional metrics logging
> For workloads with limited sequentiality, these limits reduce unnecessary 
> memory usage and background work.
> h3. Expected Impact
>  * Improve throughput for large sequential and scan workloads.
>  * Hide remote block-read latency through parallelism.
>  * Improve utilization of network and DataNode capacity.
>  * Reduce the impact of per-block RPC latency on a single reader.
>  * Preserve existing behavior when disabled.
>  * Provide tunable resource limits for different workloads.
> h2. Backward Compatibility
> The feature is {*}disabled by default{*}. Existing `DFSInputStream` behavior 
> and read paths remain unchanged unless client-side prefetching is explicitly 
> enabled.



--
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