TT Lab
开始
学习 学习路径 课程

Apache Hadoop — 在一个 Pod 里搭起并运维 HDFS 与 YARN

把 12MiB 文件切成数据块,并一路追踪到磁盘

在 TT Lab 中继续学习

目标

把 12MiB 的文件以 4MiB 的块大小上传,用 fsck 看到它被拆成三个块,并亲手确认这些块就是 DataNode 磁盘上的普通文件。同时观察:提高副本系数后,在只有一个 DataNode 的集群里会发生什么;小文件如何占用块;块大小如何改变文件校验和。

为什么重要

在 HDFS 中,块是存储、复制和并行处理的单位。文件按块大小(默认 128MB)切开,每个块独立复制到多个 DataNode,MapReduce 或 Spark 通常为每个块分配一个任务。块大小由写入方(客户端)决定,因此每个文件可以不同。 副本系数同样因文件而异。NameNode 会为每个块统计“当前有几个副本”,不足时就指示其他 DataNode 复制。如果没有可复制的目标,块就会一直处于副本不足状态,并由 fsck 报告。在生产环境中,fsck 给出的副本不足块数和缺失块数,是最先要看的健康指标。 块是 DataNode 磁盘上的普通文件,这一点在处理故障时很重要。一块磁盘坏了,上面的块文件就会消失,NameNode 通过块报告得知这一点,再从其他副本重新补齐。

步骤

  1. 在 HDFS 中创建 /user/root/blocks,并以 4MiB 的块大小(-D dfs.blocksize=4194304)把 /data/blobs/sample-12m.bin 上传为 /user/root/blocks/big.bin。
  2. 把 hdfs fsck /user/root/blocks/big.bin -files -blocks -locations 的输出保存到 /root/hdp/blocks/fsck.txt。
  3. 在 DataNode 数据目录(/var/lib/hadoop/data)下找到第一个块对应的文件,把它的绝对路径单独写成一行,保存到 /root/hdp/blocks/block0.path。
  4. 不指定块大小,把同一个本地文件上传为 /user/root/blocks/big-default.bin。
  5. 用 hdfs dfs -setrep 3 /user/root/blocks/big.bin 把副本系数提高到 3(不加 -w),并把 hdfs fsck /user/root/blocks/big.bin 的输出保存到 /root/hdp/blocks/underrep.txt。
  6. 把 /data/small/sensor-0000.csv 到 sensor-0049.csv 共 50 个文件上传到 /user/root/blocks/tiny/,并把文件数、块数和字节总数按 {"files": 정수, "blocks": 정수, "bytes": 정수} 的格式写入 /root/hdp/blocks/tiny.json(占位符依次为文件数、块数与字节总数,均为整数)。
  7. 用 hdfs dfs -checksum 分别以默认模式和 -D dfs.checksum.combine.mode=COMPOSITE_CRC 各求一次 big.bin 和 big-default.bin 的校验和,把得到的四行保存到 /root/hdp/blocks/checksum.txt。
  8. 在 /root/hdp/blocks/report.md 中写出 ## 블록으로 쪼개기、## 복제、## 체크섬 三个小节。第一节写入第 1 步的块数,第二节写入第 5 步的副本不足块数和第 6 步的块数。

参考

以 4MiB 块大小上传

在 HDFS 中创建 /user/root/blocks,并用 hdfs dfs -D dfs.blocksize=4194304 -put 把 /data/blobs/sample-12m.bin(12MiB)上传为 /user/root/blocks/big.bin。

块大小不是集群设置,而是写入时由客户端决定的值。12MiB ÷ 4MiB,先算一算会有几个块。评分器会查看 NameNode 记住的块大小和块数。

用 fsck 查看块

把 hdfs fsck /user/root/blocks/big.bin -files -blocks -locations 的输出保存到 /root/hdp/blocks/fsck.txt。

每个块占一行,显示 BP-…:blk_<ID>_<세대>、长度、存活副本数以及持有副本的 DataNode(占位符依次为块 ID 与世代号)。块池(BP)ID 是这个 NameNode 命名空间的标签。评分器会把你保存的块 ID 与当前 fsck 的结果对照。

块是磁盘上的文件

在 /var/lib/hadoop/data 下找到第 2 步中看到的第一个块对应的文件,把它的绝对路径单独写成一行,保存到 /root/hdp/blocks/block0.path。

用 find /var/lib/hadoop/data -name 'blk_<ID>' 查找(占位符为块 ID,选没有 .meta 后缀的那个)。再用 cmp 把该文件的大小和原文件前 4MiB 对比一下——HDFS 的块就是未经加工的字节片段。评分器也是这样检查的。

用默认块大小上传会怎样

不指定块大小,把同一个 /data/blobs/sample-12m.bin 上传为 /user/root/blocks/big-default.bin。

默认块大小是 128MB,所以 12MiB 的文件整个放进一个块。块比文件大,也不会每块占用 128MB 磁盘——块文件只按实际长度写入。但正如配额实验中看到的,预留是按块大小计算的。

提高副本系数,但只有一个 DataNode

用 hdfs dfs -setrep 3 /user/root/blocks/big.bin 把副本系数提高到 3(不加 -w),并把 hdfs fsck /user/root/blocks/big.bin 的输出保存到 /root/hdp/blocks/underrep.txt。

NameNode 会把目标副本数改为 3,但没有可复制的 DataNode,所以这些块会一直处于副本不足状态。请查看 fsck 摘要中的 Under-replicated blocks 和 Missing replicas。加上 -w 会等待复制完成,命令就不会返回。

小文件也是每个占一个块

把 /data/small/sensor-0000.csv 到 sensor-0049.csv 共 50 个文件上传到 /user/root/blocks/tiny/,并把该目录的文件数、块数和字节总数按 {"files": 정수, "blocks": 정수, "bytes": 정수} 的格式写入 /root/hdp/blocks/tiny.json(占位符依次为文件数、块数与字节总数,均为整数)。

每个文件只有几百字节,但每个文件仍占一个块。NameNode 把文件和块分别作为对象放在内存里,所以 50 个小文件就是 100 个对象。块数从 fsck 摘要的 Total blocks 得到,字节数用 hdfs dfs -du -s 得到。

块大小会改变校验和

把 hdfs dfs -checksum /user/root/blocks/big.bin /user/root/blocks/big-default.bin 与 hdfs dfs -D dfs.checksum.combine.mode=COMPOSITE_CRC -checksum 对同样两个文件的输出共四行,保存到 /root/hdp/blocks/checksum.txt。

默认的文件校验和是“分块 CRC 的 MD5 再做 MD5”,因此块边界会混进结果。内容相同但块大小不同,值就不同,所以在块大小不同的集群之间,distcp 的校验会对不上。COMPOSITE_CRC 生成与块边界无关的 CRC,因此给出相同的值。

用数字说明块、复制和校验和

在 /root/hdp/blocks/report.md 中写出 ## 블록으로 쪼개기、## 복제、## 체크섬 三个小节。第一节写入第 1 步的块数,第二节写入第 5 步的副本不足块数和第 6 步的块数。

各用一两句话写出:块大小由谁决定,副本不足何时出现、由谁修复,以及校验和为什么与块大小绑定。