Skip to content

HDFS-17977. Add a compact standalone HDFS DataNode read/write stress tester - #8719

Open
rdhabalia wants to merge 1 commit into
apache:trunkfrom
rdhabalia:hdfs-stress-test
Open

HDFS-17977. Add a compact standalone HDFS DataNode read/write stress tester#8719
rdhabalia wants to merge 1 commit into
apache:trunkfrom
rdhabalia:hdfs-stress-test

Conversation

@rdhabalia

Copy link
Copy Markdown

Description of PR

TestDFSIO is the standard HDFS I/O benchmark, but it is a poor fit for
targeted DataNode stress testing:

  • It launches a MapReduce job scheduled by YARN across the whole cluster, so
    it cannot generate controlled, steady QPS/throughput and takes a long time
    to saturate a targeted subset of nodes.
  • It cannot target a specific set of DataNodes, such as a single replica set,
    which is required to reproduce and measure hot or overloaded nodes.
  • It reports aggregate throughput only and does not provide client-side
    latency distributions such as p50/p95/p99, which are essential for
    characterizing tail latency and disk random-I/O behavior.
  • It requires the MapReduce/YARN stack to be available.

Approach

Add HdfsStressTest, a single-process, no-MapReduce load generator.

Because it depends only on the HDFS client (DistributedFileSystem plus
favored-nodes) and does not require MapReduce/YARN, it lives in the
hadoop-hdfs test tree (org.apache.hadoop.hdfs), alongside other standalone
HDFS benchmarks such as BenchmarkThroughput, rather than in the MapReduce
jobclient module.

The tool is intentionally compact, consisting of one tool class with small
nested helpers, and provides the controls that TestDFSIO lacks:

  • Controlled read/write throughput

    • Uses a global token-bucket rate limiter.
    • Supports an optional linear ramp from start to end throughput for
      acceleration stress testing.
  • Targeted DataNodes

    • Uses HDFS favored-nodes hints so that load is directed to a chosen
      replica set.
  • Configurable block and file size

    • Supports configurable block size.
    • Supports configurable test file size.
  • Cold-read testing

    • A pre-test phase creates a large corpus of files sized to exceed the
      DataNode page cache, for example, approximately 2x DataNode memory.
    • Because the corpus does not fit in main memory, the kernel evicts older
      pages as newer blocks are written.
    • By the time the measured phase re-reads a file, its pages are no longer
      expected to be cached, causing the measured read to fall through to disk.
    • The read workload spreads file selections across the entire corpus rather
      than replaying a hot subset, keeping the page-cache hit rate near zero.
    • This allows the tool to measure actual disk behavior rather than
      page-cache performance.
  • Client-side latency and throughput metrics

    • Reports latency distributions for reads and writes:
      • p50
      • p75
      • p95
      • p99
      • min
      • max
      • mean
      • stddev
    • Reports effective QPS and throughput for both reads and writes.

Multi-Client Scale-Out

Aggregate load can be scaled by running the tool concurrently on multiple
client hosts against the same cluster.

The offered load is the sum of each client's configured throughput.

Multi-client usage and guidance are documented, including:

  • Using distinct write/read directories per client.
  • Sharing the same favoredDataNodes configuration.
  • Running multiple instances concurrently.

Configuration

Workload configuration is specified through a properties file.

Supported properties include:

Property Description
favoredDataNodes DataNodes to target using HDFS favored-nodes hints
testWriteDirectory Directory used for write workload
testReadDirectories Directories containing the read corpus
blockSizeMB HDFS block size and I/O unit
testDurationSeconds Measured workload duration
writeThroughputMB Target write throughput
readThroughputMB Target read throughput
testReadFileSizeGB Size of the read corpus
preTestWriteThroughputMB Pre-test corpus write throughput
preTestWriteDurationSeconds Maximum duration of the pre-test phase
endWriteThroughputMB Optional final write throughput for ramping
endReadThroughputMB Optional final read throughput for ramping

Any property can be overridden using -D through ToolRunner.

Documentation

Every configuration property, the run command, cold-read/page-cache
rationale, and multi-client scale-out guidance are documented in:

  • The HdfsStressTest class Javadoc.
  • The new user guide:
    hadoop-hdfs/src/site/markdown/HdfsStressTest.md
  • The HDFS site menu, which links to the new user guide.

Run Example

hadoop jar hadoop-hdfs-<version>-tests.jar \
    org.apache.hadoop.hdfs.HdfsStressTest \
    /path/to/stress.properties

Validation

loadConfig fails fast on misconfigurations that could otherwise produce
misleading results.

Block Size Validation

blockSizeMB must be a positive number of MB.

The block size is used as the I/O unit, as well as a divisor when sizing the
corpus and calculating per-operation rates.

Read Workload Validation

When the read workload is enabled:

readThroughputMB > 0

testReadFileSizeGB must also be positive.

Reads are served only from the pre-test corpus. Without a valid corpus size,
the tool could silently run zero readers and still exit successfully.

Cold-Read Corpus Validation

The pre-test phase creates a corpus large enough to exceed the DataNode page
cache so that subsequent reads fall through to disk.

The read workload distributes file selections across the entire corpus rather
than repeatedly reading a hot subset, keeping the page-cache hit rate near
zero.

If the pre-test is time-boxed using preTestWriteDurationSeconds and stops
before reaching testReadFileSizeGB, the tool prints a WARNING.

The warning indicates that some reads may be served from the page cache and
that the resulting numbers could therefore be optimistic, rather than
silently reporting warm reads as cold.

Testing

TestHdfsStressTest

Uses MiniDFSCluster to validate individual building blocks and the
end-to-end Tool execution.

The test verifies:

  • writeBlockFile

    • Produces an exactly block-sized file.
    • Uses the configured replication factor and block size.
    • Writes the expected payload.
  • readWholeFile

    • Reads a complete block through EOF.
  • Pre-test phase

    • Creates a block-sized cold-read corpus.
    • Round-robins files across multiple directories.
    • Honors the configured duration cap.
    • Emits a warning to stderr when the capped corpus is smaller than the
      requested read corpus size.
  • Write-only workload

    • Drives the write path through ToolRunner.
    • Does not create a read corpus.

TestHdfsStressTestHelpers

Provides fast, cluster-free unit tests for pacing, measurement, and
configuration helpers.

Rate Limiter

Tests:

  • Token-bucket pacing and request spacing.
  • Runtime rate changes.

Latency Statistics

Tests:

  • Nanosecond-to-millisecond conversion.
  • Latency sorting.
  • Bounded-memory reservoir sampling.

Configuration Validation

Tests:

  • blockSizeMB must be positive.
  • Enabling the read workload requires a positive
    testReadFileSizeGB.
  • Valid read-only configurations load successfully.
  • Valid write-only configurations load successfully.

These validations prevent configurations that would otherwise silently perform
no reads or produce misleading benchmark results.

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?
  • If applicable, have you updated the LICENSE, LICENSE-binary, NOTICE-binary files?

AI Tooling

If an AI tool was used:

Motivation:
TestDFSIO is the standard HDFS I/O benchmark, but it is a poor fit for
targeted DataNode stress testing:

- It launches a MapReduce job scheduled by YARN across the whole cluster, so
  it cannot generate a controlled, steady QPS/throughput and it takes a long
  time to saturate a targeted subset of nodes.
- It cannot target a specific set of DataNodes (e.g. one replica set), which is
  exactly what is needed to reproduce and measure a hot/overloaded node.
- It reports aggregate throughput only, with no client-side latency
  distributions (p50/p95/p99), which are essential to characterise tail
  latency and disk-random-IO behaviour.
- It requires a MapReduce/YARN stack to be available at all.

Approach:
Add HdfsStressTest, a single-process, no-MapReduce load generator. Because it
depends only on the HDFS client (DistributedFileSystem plus favored-nodes) and
needs no MapReduce/YARN, it lives in the hadoop-hdfs test tree
(org.apache.hadoop.hdfs), alongside the other standalone HDFS benchmarks such
as BenchmarkThroughput, rather than in the MapReduce jobclient module. It is
intentionally compact (one tool class plus small nested helpers) and provides
the controls TestDFSIO lacks:

- Controlled read/write throughput (MB/s) enforced by a global token-bucket
  rate limiter, with an optional linear ramp (start -> end throughput) for
  acceleration stress testing.
- Targeted DataNodes via HDFS favored-nodes hints so load lands on a chosen
  replica set.
- Configurable block/file size.
- A pre-test phase that pre-creates a large corpus of files (sized to exceed
  the DataNode page cache, e.g. ~2x DataNode memory). Because the corpus does
  not fit in main memory, the kernel evicts older pages as newer blocks are
  written, so by the time the measured phase re-reads a file its pages are no
  longer cached and every measured read falls through to disk (a true cold
  read). This is how the tool avoids page-cache reads and measures real disk
  behaviour.
- Client-side latency distributions (p50, p75, p95, p99, min, max, mean,
  stddev) and effective QPS/throughput for both reads and writes.

Aggregate load can be scaled by running the tool on multiple client hosts at
once against the same cluster; the offered load is the sum of each client's
configured throughput. This is documented along with the per-client guidance
(distinct write/read directories, shared favoredDataNodes, overlapping runs).

Workload is described by a properties file (favoredDataNodes,
testWriteDirectory, testReadDirectories, blockSizeMB, testDurationSeconds,
writeThroughputMB, readThroughputMB, testReadFileSizeGB,
preTestWriteThroughputMB, preTestWriteDurationSeconds, optional
endWriteThroughputMB/endReadThroughputMB for ramping). Any property may be
overridden with -D via ToolRunner.

Documentation:
- Every configuration property, the run command, the cold-read/page-cache
  rationale and the multi-client scale-out guidance are documented both in the
  class javadoc and in a new user guide,
  hadoop-hdfs/src/site/markdown/HdfsStressTest.md (linked from the HDFS site
  menu). Run example:
    hadoop jar hadoop-hdfs-<version>-tests.jar \
        org.apache.hadoop.hdfs.HdfsStressTest /path/to/stress.properties

Validation:
- loadConfig fails fast on misconfigurations that would otherwise produce
  misleading results: blockSizeMB must be a positive number of MB (it is the
  I/O unit and a divisor when sizing the corpus and computing per-op rates),
  and enabling the read workload (readThroughputMB > 0) requires a positive
  testReadFileSizeGB, since reads are served only from the pre-test corpus and
  would otherwise silently run zero readers yet still exit success.
- The pre-test phase writes a corpus of files sized to exceed the DataNode
  page cache "once", so re-reads fall through to disk; the read workload
  spreads its picks across the whole corpus rather than replaying a hot subset,
  keeping the page-cache hit rate near zero. If the corpus is time-boxed with
  preTestWriteDurationSeconds and stops short of testReadFileSizeGB, the tool
  prints a WARNING that the reads may be served from the page cache (so the
  numbers can be optimistic) instead of silently reporting warm reads as cold.

Testing:
- TestHdfsStressTest (MiniDFSCluster) validates the individual building blocks
  and the end-to-end Tool run: writeBlockFile produces an exactly block-sized
  file with the configured replication/block size and payload; readWholeFile
  reads a full block to EOF; the pre-test phase creates a block-sized cold-read
  corpus round-robined across multiple directories and honours the duration
  cap (and warns on stderr when the capped corpus is smaller than requested);
  and a write-only run drives the write path through ToolRunner without
  creating a read corpus.
- TestHdfsStressTestHelpers adds fast, cluster-free unit tests for the pacing
  and measurement helpers (token-bucket RateLimiter spacing, runtime rate
  changes, LatencyStats nanos->millis sorting and bounded-memory reservoir
  sampling) and for config validation: blockSizeMB must be positive, enabling
  the read workload requires a positive testReadFileSizeGB (otherwise the run
  would silently do no reads), and valid read-only / write-only configs load
  without error.
@hadoop-yetus

Copy link
Copy Markdown

💔 -1 overall

Vote Subsystem Runtime Logfile Comment
+0 🆗 reexec 0m 21s Docker mode activated.
_ Prechecks _
+1 💚 dupname 0m 0s No case conflicting files found.
+0 🆗 codespell 0m 0s codespell was not available.
+0 🆗 detsecrets 0m 0s detect-secrets was not available.
+0 🆗 markdownlint 0m 0s markdownlint was not available.
+0 🆗 xmllint 0m 1s xmllint was not available.
+1 💚 @author 0m 0s The patch does not contain any @author tags.
+1 💚 test4tests 0m 0s The patch appears to include 3 new or modified test files.
_ trunk Compile Tests _
+0 🆗 mvndep 2m 25s Maven dependency ordering for branch
+1 💚 mvninstall 29m 12s trunk passed
+1 💚 compile 9m 36s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 compile 9m 44s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+1 💚 checkstyle 3m 35s trunk passed
+1 💚 mvnsite 1m 29s trunk passed
+1 💚 javadoc 1m 16s trunk passed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu
+1 💚 javadoc 1m 11s trunk passed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu
+0 🆗 spotbugs 0m 25s branch/hadoop-project no spotbugs output file (spotbugsXml.xml)
+1 💚 shadedclient 19m 14s branch has no errors when building and testing our client artifacts.
_ Patch Compile Tests _
+0 🆗 mvndep 0m 18s Maven dependency ordering for patch
-1 ❌ mvninstall 0m 20s /patch-mvninstall-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
-1 ❌ compile 1m 10s /patch-compile-root-jdkUbuntu-21.0.12+8-1-24.04-Ubuntu.txt root in the patch failed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu.
-1 ❌ javac 1m 10s /patch-compile-root-jdkUbuntu-21.0.12+8-1-24.04-Ubuntu.txt root in the patch failed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu.
-1 ❌ compile 1m 17s /patch-compile-root-jdkUbuntu-17.0.20+8-1-24.04-Ubuntu.txt root in the patch failed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu.
-1 ❌ javac 1m 17s /patch-compile-root-jdkUbuntu-17.0.20+8-1-24.04-Ubuntu.txt root in the patch failed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu.
+1 💚 blanks 0m 0s The patch has no blanks issues.
-0 ⚠️ checkstyle 3m 11s /results-checkstyle-root.txt root: The patch generated 2 new + 0 unchanged - 0 fixed = 2 total (was 0)
-1 ❌ mvnsite 0m 21s /patch-mvnsite-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
-1 ❌ javadoc 0m 18s /patch-javadoc-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-21.0.12+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-21.0.12+8-1-24.04-Ubuntu.
-1 ❌ javadoc 0m 21s /patch-javadoc-hadoop-hdfs-project_hadoop-hdfs-jdkUbuntu-17.0.20+8-1-24.04-Ubuntu.txt hadoop-hdfs in the patch failed with JDK Ubuntu-17.0.20+8-1-24.04-Ubuntu.
+0 🆗 spotbugs 0m 11s hadoop-project has no data from spotbugs
-1 ❌ spotbugs 0m 22s /patch-spotbugs-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
-1 ❌ shadedclient 5m 1s patch has errors when building and testing our client artifacts.
_ Other Tests _
+1 💚 unit 0m 10s hadoop-project in the patch passed.
-1 ❌ unit 0m 18s /patch-unit-hadoop-hdfs-project_hadoop-hdfs.txt hadoop-hdfs in the patch failed.
+1 💚 asflicense 0m 21s The patch does not generate ASF License warnings.
99m 2s
Subsystem Report/Notes
Docker ClientAPI=1.56 ServerAPI=1.56 base: https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8719/1/artifact/out/Dockerfile
GITHUB PR #8719
Optional Tests dupname asflicense mvnsite codespell detsecrets markdownlint compile javac javadoc mvninstall unit shadedclient spotbugs checkstyle xmllint
uname Linux 9a868832f9ce 5.15.0-190-generic #200-Ubuntu SMP Fri Aug 7 15:06:04 UTC 2026 x86_64 x86_64 x86_64 GNU/Linux
Build tool maven
Personality dev-support/bin/hadoop.sh
git revision trunk / 5935cb9
Default Java Ubuntu-17.0.20+8-1-24.04-Ubuntu
Multi-JDK versions /usr/lib/jvm/java-21-openjdk-amd64:Ubuntu-21.0.12+8-1-24.04-Ubuntu /usr/lib/jvm/java-17-openjdk-amd64:Ubuntu-17.0.20+8-1-24.04-Ubuntu
Test Results https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8719/1/testReport/
Max. process+thread count 610 (vs. ulimit of 10000)
modules C: hadoop-project hadoop-hdfs-project/hadoop-hdfs U: .
Console output https://ci-hadoop.apache.org/job/hadoop-multibranch/job/PR-8719/1/console
versions git=2.43.0 maven=3.9.15 spotbugs=4.9.7
Powered by Apache Yetus 0.14.1 https://yetus.apache.org

This message was automatically generated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants