20000 个文件跑了 11500 秒:你压的是 YARN 调度器,不是 HDFS
关键词:TestDFSIO、HDFS 基准测试、YARN 调度器、maximum-offswitch-assignments、心跳间隔、容器分配速率、Hadoop 性能测试、TeraSort、小文件、基准测试设计
目录
- 一、先说结论
- 二、测试现场
- [三、结果:五轮写入,稳定得不像 I/O](#三、结果:五轮写入,稳定得不像 I/O "#%E4%B8%89%E7%BB%93%E6%9E%9C%E4%BA%94%E8%BD%AE%E5%86%99%E5%85%A5%E7%A8%B3%E5%AE%9A%E5%BE%97%E4%B8%8D%E5%83%8F-io")
- 四、第一反应:是不是磁盘不行
- [五、转折:有人问了一句"分配 container 要多久"](#五、转折:有人问了一句"分配 container 要多久" "#%E4%BA%94%E8%BD%AC%E6%8A%98%E6%9C%89%E4%BA%BA%E9%97%AE%E4%BA%86%E4%B8%80%E5%8F%A5%E5%88%86%E9%85%8D-container-%E8%A6%81%E5%A4%9A%E4%B9%85")
- 六、算账:集群每秒能发多少个任务
- 七、三个参数锁死了调度速率
- [八、1333 秒只是下限](#八、1333 秒只是下限 "#%E5%85%AB1333-%E7%A7%92%E5%8F%AA%E6%98%AF%E4%B8%8B%E9%99%90")
- [九、90% 的时间,磁盘在空转](#九、90% 的时间,磁盘在空转 "#%E4%B9%9D90-%E7%9A%84%E6%97%B6%E9%97%B4%E7%A3%81%E7%9B%98%E5%9C%A8%E7%A9%BA%E8%BD%AC")
- [十、读取为什么快 2.1 倍](#十、读取为什么快 2.1 倍 "#%E5%8D%81%E8%AF%BB%E5%8F%96%E4%B8%BA%E4%BB%80%E4%B9%88%E5%BF%AB-21-%E5%80%8D")
- [十一、同一批测试里的 TeraSort](#十一、同一批测试里的 TeraSort "#%E5%8D%81%E4%B8%80%E5%90%8C%E4%B8%80%E6%89%B9%E6%B5%8B%E8%AF%95%E9%87%8C%E7%9A%84-terasort")
- 十二、怎么改:少任务,大文件
- 十三、如果真的要压小文件
- 十四、复盘
一、先说结论
5 节点的 HDFS 集群,TestDFSIO 写 20000 个 100MB 文件,五轮平均耗时 11572 秒 (约 3.2 小时),吞吐只有 177 MB/s。
第一反应一定是"磁盘不行"或者"网络不行"。
但算完一笔账之后,结论是另一个方向:
这批数据不能代表 HDFS 的性能。它测的是 YARN 控制平面的任务分发能力。
支撑这个结论的有四层证据:
- 调度速率被三个参数锁死:全集群每秒最多分发 15 个容器,20000 个 task 光"发号"就要 1333 秒
- 动态心跳是关闭的:节点没有任何加速汇报的可能,即使任务队列堆积如山
- 五轮耗时极差只有 4.2%,读取 4 轮只有 1% :这种一致性是确定性瓶颈的特征,不是 I/O 抖动
- 单任务粒度太小:每个 task 只写 100MB(约 1 秒的 I/O),却要走完整的容器申请与 JVM 启动流程
一句话:
你测到的不是"字节吞吐",是"任务吞吐"。
二、测试现场
2.1 命令
arduino
hadoop jar hadoop-mapreduce-client-jobclient-3.3.3-tests.jar TestDFSIO -write -nrFiles 20000 -fileSize 100
| 项 | 值 |
|---|---|
| 文件数 | 20000 |
| 单文件大小 | 100 MB |
| 总数据量 | 20000 × 100MB = 2 TB |
| 集群规模 | 5 节点(2 NN + 3~5 DN/NM) |
| 写入轮次 | 5 |
| 读取轮次 | 4 |
-nrFiles 20000 这个参数,直接决定了这个测试会创建 20000 个 map task。
而 20000 个 task,就是这个问题的起点。
2.2 基准脚本
bash
#!/bin/bash
# hadoop_benchmark.sh
HADOOP_BIN="/opt/hadoop/bin/hadoop"
TEST_JAR="/opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.3.3-tests.jar"
EXAMPLE_JAR="/opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.3.jar"
LOG_FILE="./benchmark_$(date +%Y%m%d-%H%M%S).log"
CSV_FILE="./benchmark_result_$(date +%Y%m%d-%H%M%S).csv"
RUN_TIMES=${1:-1}
MODE=${2:-"dfsio-write"}
echo "round,test_type,start_time,end_time,cost_seconds" > $CSV_FILE
clean_hdfs() {
$HADOOP_BIN fs -rm -r -skipTrash /test/terasort-input >/dev/null 2>&1
$HADOOP_BIN fs -rm -r -skipTrash /test/terasort-output >/dev/null 2>&1
$HADOOP_BIN fs -rm -r -skipTrash /benchmarks/TestDFSIO* >/dev/null 2>&1
}
run_test() {
local i=$1
clean_hdfs
START_TIME=$(date +%s); START_HUMAN=$(date "+%Y-%m-%d %H:%M:%S")
case $MODE in
dfsio-write) $HADOOP_BIN jar $TEST_JAR TestDFSIO -write -nrFiles 20000 -fileSize 100 | tee -a $LOG_FILE ;;
dfsio-read) $HADOOP_BIN jar $TEST_JAR TestDFSIO -read -nrFiles 20000 -fileSize 100 | tee -a $LOG_FILE ;;
teragen) $HADOOP_BIN jar $EXAMPLE_JAR teragen 10000000000 /test/terasort-input | tee -a $LOG_FILE ;;
terasort) $HADOOP_BIN jar $EXAMPLE_JAR terasort /test/terasort-input /test/terasort-output | tee -a $LOG_FILE ;;
*) echo "[ERROR] Unknown mode: $MODE"; exit 1 ;;
esac
END_TIME=$(date +%s); END_HUMAN=$(date "+%Y-%m-%d %H:%M:%S")
COST=$((END_TIME - START_TIME))
echo "$i,$MODE,$START_HUMAN,$END_HUMAN,$COST" >> $CSV_FILE
}
for ((i=1; i<=RUN_TIMES; i++)); do run_test $i; done
脚本本身没问题------清理、计时、落 CSV、多轮循环都有。
问题不在脚本,在参数。
三、结果:五轮写入,稳定得不像 I/O
3.1 写入 5 轮
| 轮次 | 耗时(秒) |
|---|---|
| 1 | 11855 |
| 2 | 11538 |
| 3 | 11701 |
| 4 | 11399 |
| 5 | 11370 |
| 平均 | 11572 |
极差 485 秒,波动率 4.2%。
3.2 读取 4 轮
| 轮次 | 耗时(秒) |
|---|---|
| 1 | 5324 |
| 2 | 5360 |
| 3 | 5304 |
| 4 | 5341 |
| 平均 | 5332 |
极差 56 秒,波动率 1.05%。
3.3 换算吞吐
bash
写入:2 TB ÷ 11572 s ≈ 177 MB/s
读取:2 TB ÷ 5332 s ≈ 384 MB/s
3.4 这里有个细节值得盯一下
读取 4 轮的波动只有 1%。
真实的磁盘 I/O 很难这么稳------页缓存命中率、后台 compaction、GC、网络抖动,都会让结果上下浮动个几秒到几十秒。
1% 的波动率,说明瓶颈是确定性的、每次都会发生、且每次都消耗几乎相同的时间。
这不是"磁盘状态有波动"的特征,是"每个任务都要走一遍固定流程"的特征。
四、第一反应:是不是磁盘不行
看到 177 MB/s,第一反应是排查硬件:
| 检查项 | 结果 |
|---|---|
| 磁盘健康(SMART / iostat) | 正常 |
| 网络带宽 | 正常 |
| DataNode 存活 | 5 台都在 |
| 副本数 / 块大小 | 默认,正常 |
| NameNode RPC 队列 | 不积压 |
硬件层面没有明显短板。
照这个方向继续查下去,会陷入"每块盘看起来都正常,但整体就是慢"的困境。
五、转折:有人问了一句"分配 container 要多久"
当时已经准备去测单盘 IOPS 了。
然后被问了一个很简单的问题:
"20000 个 map,光分配 container 要多久?跟 HDFS 性能有关系吗?"
这句话把方向整个掰了过来。
因为 TestDFSIO 的 20000 个文件 = 20000 个 map task,而每一个 task 都必须:
排队 → 向 RM 申请容器 → 拿到容器 → 启动 JVM → 干活 → 回收
"干活"只是这条链上的一环。
如果这条链的入口 每秒只能放进 15 个,那 20000 个就要 1300 多秒------这跟磁盘快慢一点关系都没有。
六、算账:集群每秒能发多少个任务
YARN 是拉取式调度:ResourceManager 不会主动把任务推给节点,必须等 NodeManager 发心跳来领。
所以"每秒能派发多少任务"由三个东西决定:
分配速率 = 计算节点数 × 心跳频率 × 单次心跳可分配容器数
代入实测参数:
ini
计算节点数 : 3(5 节点集群中 2 台是 NN)
心跳频率 : 1 次/秒(1000ms)
单次可分配容器数 : 5
分配速率 = 3 × 1 × 5 = 15 容器/秒
6.1 20000 个任务需要多久才能"发完"
yaml
20000 ÷ 15 ≈ 1333 秒 (约 22 分钟)
如果 5 个计算节点全在(而不是 3 个):
ini
5 × 1 × 5 = 25 容器/秒
20000 ÷ 25 = 800 秒 (约 13 分钟)
光把任务派发下去,最少也要 13--22 分钟。
6.2 这段时间里集群在干什么
任务不是"一次性全发下去然后同时跑",而是:
ini
t=0s 发出第 1--15 个,开始跑
t=1s 发出第 16--30 个
t=2s ...
↓
前面发下去的任务早就跑完了(每个只写 100MB)
后面的任务还在排队等号
↓
集群的真实状态:跑一阵,等一阵
集群不是被数据压垮的,是被"发号"的速度限制住的。
七、三个参数锁死了调度速率
这三个数字都不是拍脑袋,全部来自配置和源码。
7.1 maximum-offswitch-assignments = 5
ini
yarn.scheduler.capacity.per-node-heartbeat.maximum-offswitch-assignments = 5
这个参数的含义是:每个节点、每次心跳,最多分配多少个"非本地(off-switch)"容器。
默认值就是 5。
这是 Capacity Scheduler 的保护机制:防止一次心跳把大量容器塞给一个节点,造成节点过载和调度抖动。
它就是那个"每秒最多领 5 个号"的来源。
7.2 heartbeat-interval-ms = 1000
ini
yarn.resourcemanager.nodemanagers.heartbeat-interval-ms = 1000
NodeManager 每秒向 RM 汇报一次。
源码里它是硬编码的默认值:
arduino
// YarnConfiguration.java
public static final int DEFAULT_RM_NM_HEARTBEAT_INTERVAL_MS = 1000;
7.3 heartbeat-interval-scaling-enable = false(最关键的一个)
ini
yarn.resourcemanager.nodemanagers.heartbeat-interval-scaling-enable = false
这一项才是让人绝望的地方。
YARN 其实提供了一个"动态心跳"机制:当队列堆积时,可以让节点加快汇报频率。
ini
# 动态心跳的相关参数
yarn.resourcemanager.nodemanagers.heartbeat-interval-scaling-enable = false
yarn.resourcemanager.nodemanagers.heartbeat-interval-min-ms = 1000
yarn.resourcemanager.nodemanagers.heartbeat-interval-max-ms = 1000
但 scaling-enable 默认是 false。
也就是说:
系统完全忽略 min-ms / max-ms 的调整逻辑,强制使用固定的 1000ms。
NodeManager 没有任何加速汇报状态的可能------哪怕任务队列堆到两万个,它依然保持"每秒一次"的节奏。
7.4 三个参数合起来
ini
scaling-enable = false → 心跳频率锁死在 1 Hz,不能加速
heartbeat-interval-ms = 1000 → 每秒只有 1 次机会
maximum-offswitch-assignments = 5 → 每次机会最多领 5 个
↓
每个节点每秒最多 5 个容器
↓
整个集群每秒最多 15 个(3 个计算节点)
八、1333 秒只是下限
1333 秒是"任务全部就绪、资源充足、完美匹配"情况下的理论最小值。
实际还要叠加三块开销:
| 开销 | 量级 | 说明 |
|---|---|---|
| AM ↔ RM 交互延迟 | 每次约 2 秒 | ApplicationMaster 心跳与资源协商 |
| JVM 启动/销毁 | 1--3 秒/任务 | 每个 map task 都要起一个 JVM |
| 资源碎片等待 | 不确定 | 偶发性的等待,可能重试(speculative / retry) |
所以真实的"任务级固定开销"远大于 1333 秒。
这也解释了为什么 11572 秒会出现在这么"整齐"的区间里------因为它不是被 I/O 决定的,是被这条流水线的节奏决定的。
九、90% 的时间,磁盘在空转
9.1 每个 task 到底干了多少活
bash
单文件大小 : 100 MB
单个 task : 写 100 MB
按单盘 100 MB/s 估算 : 约 1 秒
每个 task 实际搬数据的时间,只有 1 秒左右。
但每个 task 的完整生命周期是:
ResourceManager 分配容器
↓
NodeManager 创建容器目录
↓
启动 JVM
↓
加载 Hadoop 配置
↓
建立 HDFS 连接(含 Kerberos 认证)
↓
写入 100MB ← 干活的部分,约 1 秒
↓
关闭文件、汇报状态、回收容器
开销是干活的数倍。
9.2 那真实带宽是多少
按经验估算,这类"小文件 + 海量任务"的评测里,真正在写数据的时间通常只占总时长的 5%--10% 。
反推一下:
yaml
总时长 11572 s
有效 I/O 时间 ≈ 1157 s(按 10% 估)
真实写入带宽 ≈ 2048000 MB ÷ 1157 s ≈ 1770 MB/s ≈ 1.7 GB/s
注意这是推算值,不是实测值。 但它指出了一个量级差:
如果把这个测试改对,量出来的结果可能是 1.7 GB/s 量级 ,而不是报告上的 177 MB/s。 差了将近十倍。
而那 90% 的时间里,磁盘在干什么?
在等。
十、读取为什么快 2.1 倍
读取 5332s,写入 11572s,比例 2.16 倍。
这个比例同时被三层因素影响:
| 层 | 写入 | 读取 |
|---|---|---|
| 调度开销(共同下限) | 约 800--1333s | 约 800--1333s |
| 单任务开销 | 建文件、分配块、写 pipeline | 只读,流程更短 |
| 实际 I/O | 2TB 写入 | 2TB 读取 |
HDFS 本身"读快写慢"是正常的(写入要走 3 副本 pipeline,读取可以直接从最近副本读)。
但有个反直觉的点:
因为两边都垫着同一块固定的调度成本,"2.1 倍"这个比值是被稀释过的。
也就是说,真实的磁盘读写性能差距,很可能比 2.1 倍更大------把这个固定成本扣掉之后,差距才会显出来。
十一、同一批测试里的 TeraSort
同一批基准里还跑了 MapReduce 计算性能:
| 测试 | 参数 | 耗时 |
|---|---|---|
| TeraGen | 10,000,000,000 行 | 4714 秒(约 1.3 小时) |
| TeraSort | 1 TB | 741 秒(约 12.3 分钟) |
这两组数据的价值,不在于和 TestDFSIO 做性能对比(测试对象不同),而在于:
集群在连续数小时的压力测试下,没有出现服务中断、节点掉线、任务大面积失败。
一次测错的基准,数据不能用来评估性能,但可以证明"能撑住" 。
这也是这次测试唯一可靠的产出。
十二、怎么改:少任务,大文件
核心原则只有一条:
css
单任务 I/O 时间 >> 单任务启动开销
12.1 参数怎么改
| 调整项 | 原来 | 改成 | 理由 |
|---|---|---|---|
| 文件数 | 20000 | 100 | 任务数降两个数量级,调度几秒内完成 |
| 单文件大小 | 100 MB | 10 GB | 单任务 I/O 从 1s 提到 100s |
| 总数据量 | 2 TB | 1 TB | 测试时长可控 |
12.2 新命令
perl
# 写入
hadoop jar hadoop-mapreduce-client-jobclient-3.3.3-tests.jar \
TestDFSIO -write -nrFiles 100 -fileSize 10000MB
# 读取
hadoop jar hadoop-mapreduce-client-jobclient-3.3.3-tests.jar \
TestDFSIO -read -nrFiles 100 -fileSize 10000MB
12.3 为什么这样就对了
css
原来:20000 × 100MB
单任务 I/O ≈ 1s,启动开销 ≈ 2s
→ 开销占比 ≈ 66%,调度耗时 ≈ 1333s
改后:100 × 10GB
单任务 I/O ≈ 100s,启动开销 ≈ 2s
→ 开销占比 ≈ 2%,调度耗时 ≈ 7s
同样的思路,从"测任务吞吐"变成"测字节吞吐"。
12.4 预期结果与判定标准
| 指标 | 预期 |
|---|---|
| 调度开销 | < 10 秒 |
| 测试总时长 | 完全由磁盘写入速度决定 |
| 吞吐 | 大幅提升,接近硬件物理极限 |
判定方法:
- 如果吞吐显著提升 → 之前的瓶颈确实是调度,结论成立
- 如果吞吐几乎没变 → 这时候才轮到查磁盘、查网络、查副本策略
十三、如果真的要压小文件
有一种场景是合理的:你就是要评估"海量小文件"对集群的冲击。
这时候要测的不是 HDFS 带宽,而是 YARN 调度器 + NameNode 元数据的能力。
13.1 临时放开调度限制(测试后必须还原)
ini
# 开启动态心跳
yarn.resourcemanager.nodemanagers.heartbeat-interval-scaling-enable = true
# 允许最快 100ms 一次心跳
yarn.resourcemanager.nodemanagers.heartbeat-interval-min-ms = 100
# 单次心跳放开到 100 个容器
yarn.scheduler.capacity.per-node-heartbeat.maximum-offswitch-assignments = 100
改完之后,分配速率从:
ini
3 × 1 × 5 = 15 /s
变成:
ini
3 × 10 × 100 = 3000 /s
理论上快了 200 倍。
13.2 三个必须提醒的地方
① 这组参数有风险
maximum-offswitch-assignments 调大,会让单节点在极短时间内被塞入大量容器,可能造成:
- NodeManager 本地磁盘 IO 打满
- 容器启动风暴,JVM 争抢 CPU
- 调度器抖动,影响其他队列
② 必须还原
压测完立刻改回默认值。这类参数一旦遗留在生产环境,下一次流量高峰可能就是事故。
③ 不要用改参数来"美化" HDFS 带宽测试
你如果只是想测磁盘,改参数是错误的方向------那是在改被测系统,而不是改测试方法。
十四、复盘
14.1 六个判断
① 基准测试的第一步,是算清楚"这套测试最快能跑多快"
理论下限 1333 秒,实测 11572 秒 ------ 先算天花板,才知道大头在哪。
② "结果太稳定"本身就是一个信号
读取 4 轮波动 1%、写入 5 轮波动 4.2%。当一个本该有抖动的指标变得极其稳定时,说明瓶颈是确定性的,不是物理的。
③ 拉取式调度系统,天然有"发号上限"
YARN、K8s、Mesos 都是拉取式。
它们的能力上限不是"能跑多快",而是"每秒能派出去多少"。
④ 动态心跳默认关闭,是很多人不知道的一层
heartbeat-interval-scaling-enable=false 意味着堆积不会触发加速。
很多人以为"队列长了系统会自己加快",不会。
⑤ 任务粒度决定了你测的是"任务吞吐"还是"字节吞吐"
20000 × 100MB 和 100 × 10GB,前者测调度器,后者测磁盘。
任务数超过某个量级,被测对象就自动换了。
⑥ 测错的基准不是废数据
这次 11500 秒不能评估 HDFS 性能,但证明了集群在 3 小时连续压力下稳定运行。
很多测试的价值,不在它原本要测的方向上。
14.2 下次做基准测试前的检查清单
| 检查项 | 怎么判断 |
|---|---|
| 任务数是否合适 | 总任务数 ÷ 调度速率 应远小于预估总耗时 |
| 单任务 I/O 是否够大 | 单任务 I/O 时间应 ≥ 启动开销的 10 倍 |
| 是否已知调度速率 | 节点数 × 心跳频率 × 单次分配数 |
| 动态心跳是否开启 | heartbeat-interval-scaling-enable |
| 结果波动是否合理 | 波动过小 → 怀疑确定性瓶颈 |
| 读/写是否分开 | 分开跑,不要混在一轮里 |
| 是否动了生产参数 | 不应该动 |
附:改进版脚本
bash
#!/bin/bash
# hadoop_benchmark.sh ------ 两段式:大文件测 I/O,小文件测调度
HADOOP_BIN="/opt/hadoop/bin/hadoop"
TEST_JAR="/opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-client-jobclient-3.3.3-tests.jar"
EXAMPLE_JAR="/opt/hadoop/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.3.3.jar"
STAMP=$(date +%Y%m%d-%H%M%S)
LOG_FILE="./benchmark_${STAMP}.log"
CSV_FILE="./benchmark_result_${STAMP}.csv"
RUN_TIMES=${1:-1}
MODE=${2:-"dfsio-write-big"}
echo "round,test_type,start_time,end_time,cost_seconds" > "$CSV_FILE"
clean_hdfs() {
echo "[INFO] cleaning HDFS..." | tee -a "$LOG_FILE"
$HADOOP_BIN fs -rm -r -skipTrash /test/terasort-input >/dev/null 2>&1
$HADOOP_BIN fs -rm -r -skipTrash /test/terasort-output >/dev/null 2>&1
$HADOOP_BIN fs -rm -r -skipTrash /benchmarks/TestDFSIO* >/dev/null 2>&1
}
run_test() {
local i=$1
echo "" | tee -a "$LOG_FILE"
echo "---------- Round $i ($MODE) ----------" | tee -a "$LOG_FILE"
clean_hdfs
local START_TIME START_HUMAN END_TIME END_HUMAN COST
START_TIME=$(date +%s)
START_HUMAN=$(date "+%Y-%m-%d %H:%M:%S")
case $MODE in
# 大文件:测真实 I/O 带宽(推荐)
dfsio-write-big) $HADOOP_BIN jar $TEST_JAR TestDFSIO -write -nrFiles 100 -fileSize 10000MB | tee -a "$LOG_FILE" ;;
dfsio-read-big) $HADOOP_BIN jar $TEST_JAR TestDFSIO -read -nrFiles 100 -fileSize 10000MB | tee -a "$LOG_FILE" ;;
# 小文件:测调度与元数据压力(对比用)
dfsio-write-small) $HADOOP_BIN jar $TEST_JAR TestDFSIO -write -nrFiles 20000 -fileSize 100 | tee -a "$LOG_FILE" ;;
dfsio-read-small) $HADOOP_BIN jar $TEST_JAR TestDFSIO -read -nrFiles 20000 -fileSize 100 | tee -a "$LOG_FILE" ;;
# 计算性能
teragen) $HADOOP_BIN jar $EXAMPLE_JAR teragen 10000000000 /test/terasort-input | tee -a "$LOG_FILE" ;;
terasort) $HADOOP_BIN jar $EXAMPLE_JAR terasort /test/terasort-input /test/terasort-output | tee -a "$LOG_FILE" ;;
*) echo "[ERROR] Unknown mode: $MODE" | tee -a "$LOG_FILE"; exit 1 ;;
esac
END_TIME=$(date +%s)
END_HUMAN=$(date "+%Y-%m-%d %H:%M:%S")
COST=$((END_TIME - START_TIME))
echo "[RESULT] Round $i cost: ${COST}s" | tee -a "$LOG_FILE"
echo "$i,$MODE,$START_HUMAN,$END_HUMAN,$COST" >> "$CSV_FILE"
}
for ((i=1; i<=RUN_TIMES; i++)); do
run_test "$i"
done
echo "" | tee -a "$LOG_FILE"
echo "=========== Completed. CSV: $CSV_FILE ===========" | tee -a "$LOG_FILE"
用法:
bash
# 大文件写入(测 I/O 带宽)
./hadoop_benchmark.sh 1 dfsio-write-big
# 小文件写入(对照:看调度影响)
./hadoop_benchmark.sh 1 dfsio-write-small
# TeraGen + TeraSort
./hadoop_benchmark.sh 1 teragen && ./hadoop_benchmark.sh 1 terasort
最后一句
这次测试最有价值的产出,不是那 177 MB/s,而是想明白了一件事:
当你测一个系统时,如果测试本身的开销超过了被测对象的开销, 你测到的就是测试框架,不是那个系统。
下次跑基准之前,先花五分钟算一下"这套测试最快能跑多快"。
五分钟的算术,能省下三小时的白跑。