Apache Hadoop — 1つのPodにHDFSとYARNを立てて運用する
12MiB のファイルをブロックに分け、ディスクまで追いかける
目標
12MiBのファイルをブロック4MiBでアップロードし、3つのブロックに分割されるのをfsckで見て、そのブロックがDataNodeのディスク上の普通のファイルであることを、自分で見つけて確認します。レプリケーション係数を上げたとき、DataNodeが1台だけのクラスターで何が起きるか、小さなファイルがブロックをどう消費するか、ブロックサイズがファイルチェックサムをどう変えるかも見ます。
なぜ重要なのか
HDFSで、ブロックは保存・レプリケーション・並列処理の単位です。ファイルはブロックサイズ(デフォルト128MB)で分割され、各ブロックが独立して複数のDataNodeにレプリケートされ、MapReduceやSparkは、たいていブロック1つにタスク1つを割り当てます。ブロックサイズを決めるのは書き込む側(クライアント)なので、ファイルごとに違うことがあります。 レプリケーション係数もファイルごとに違います。NameNodeは、ブロックごとに「今レプリカがいくつあるか」を数え、足りなければ別のDataNodeへのコピーを指示します。コピーする場所がなければ、レプリケーション不足の状態のまま残り、fsckがそれを報告します。本番では、fsckのレプリケーション不足・欠落ブロックの数値が、最初に見るヘルス指標です。 ブロックがDataNodeのディスク上の普通のファイルだという事実は、障害を扱うときに重要です。ディスク1つが死ぬと、その上のブロックファイルが失われ、NameNodeは、ブロックレポートでそれを知って、別のレプリカから再び埋めます。
ステップ
- /user/root/blocksをHDFSに作成し、
/data/blobs/sample-12m.binを、ブロックサイズ4MiB(-D dfs.blocksize=4194304)で、/user/root/blocks/big.binにアップロードしてください。 hdfs fsck /user/root/blocks/big.bin -files -blocks -locationsの出力を、/root/hdp/blocks/fsck.txtに保存してください。- 最初のブロックのファイルをDataNodeのデータディレクトリ(
/var/lib/hadoop/data)の下から探して、その絶対パスを、/root/hdp/blocks/block0.pathに1行で書いてください。 - 同じローカルファイルを、ブロックサイズを指定せずに、/user/root/blocks/big-default.binとしてアップロードしてください。
hdfs dfs -setrep 3 /user/root/blocks/big.binでレプリケーション係数を3に上げ(-wなしで)、hdfs fsck /user/root/blocks/big.binの出力を、/root/hdp/blocks/underrep.txtに保存してください。/data/small/sensor-0000.csv–sensor-0049.csvの50個を、HDFSにアップロードしてください(アップロード先: /user/root/blocks/tiny/)。そのディレクトリのファイル数・ブロック数・バイト数の合計を、/root/hdp/blocks/tiny.jsonに{"files": 정수, "blocks": 정수, "bytes": 정수}の形式で書き込んでください(プレースホルダーは順に整数、整数、整数です)。hdfs dfs -checksumで、big.binとbig-default.binのチェックサムを、デフォルトモードで1回、-D dfs.checksum.combine.mode=COMPOSITE_CRCで1回求めて、4行を、/root/hdp/blocks/checksum.txtに保存してください。- /root/hdp/blocks/report.mdに、
## 블록으로 쪼개기・## 복제・## 체크섬の3つの節を書いてください(見出しは韓国語で、順に「ブロックへの分割」「レプリケーション」「チェックサム」を意味します)。最初の節にステップ1のブロック数を、2つ目の節にステップ5のレプリケーション不足のブロック数とステップ6のブロック数を入れてください。
参考
- ブロックファイルは、
/var/lib/hadoop/data/current/BP-<블록 풀 ID>/current/finalized/subdir*/subdir*/blk_<ID>です。隣のblk_<ID>_<세대>.metaは、チェックサムファイルです(プレースホルダーは順にブロックプールID、世代です)。find /var/lib/hadoop/data -name 'blk_<ID>'で探してください。 -setrep -wは、レプリケーションがすべて終わるまで待ちますが、DataNodeが1台なので、永遠に終わりません。-wなしで使ってください。- fsckはシェルコマンド(
hdfs fsck)のほかにも、NameNodeのWebの/fsck?ugi=root&path=...&files=1&blocks=1から呼び出してみることもできます。 - よくあるミス: ブロックサイズを1MiBより小さく指定すること(
dfs.namenode.fs-limits.min-block-sizeに引っかかります)、.metaファイルをブロックファイルとして書くこと。 - 公式ドキュメント: HDFS Architecture — Data Replication・HDFS Commands — fsck・hdfs-default.xml・FileSystem Shell — checksum
ブロック4MiBでアップロードする
/user/root/blocksをHDFSに作成し、/data/blobs/sample-12m.bin(12MiB)を、hdfs dfs -D dfs.blocksize=4194304 -putで、/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が1行ずつ出ます。ブロックプール(BP)IDは、このNameNodeの名前空間のラベルです。採点ツールは、自分で保存したブロックIDを、今のfsckの結果と比べます。
ブロックはディスク上のファイルである
ステップ2で見た最初のブロックのファイルを、/var/lib/hadoop/dataの下から探して、その絶対パスを、/root/hdp/blocks/block0.pathに1行で書いてください。
find /var/lib/hadoop/data -name 'blk_<ID>'で探します(.metaが付いていないほう)。そのファイルのサイズと、元データの先頭4MiBを、cmpで比べてみてください。HDFSのブロックは、加工されていないバイトの断片です。採点ツールもそのように確認します。
デフォルトのブロックサイズでアップロードすると
同じ/data/blobs/sample-12m.binを、ブロックサイズを指定せずに、/user/root/blocks/big-default.binとしてアップロードしてください。
デフォルトのブロックサイズは128MBなので、12MiBのファイルはブロック1つに収まります。ブロックがファイルより大きくても、ディスクを128MBずつ消費するわけではありません。ブロックファイルは、実際の長さの分だけ書きます。ただし、クォータのラボで見るように、予約はブロックサイズ単位で行われます。
レプリケーション係数を上げたのにDataNodeが1台だったら
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を指定すると、このレプリケーションが終わるのを待つので、コマンドが戻ってきません。
小さなファイルもブロック1つずつ
/data/small/sensor-0000.csv–sensor-0049.csvの50個を、HDFSにアップロードしてください(アップロード先: /user/root/blocks/tiny/)。そのディレクトリのファイル数・ブロック数・バイト数の合計を、/root/hdp/blocks/tiny.jsonに{"files": 정수, "blocks": 정수, "bytes": 정수}の形式で書き込んでください(プレースホルダーは順に整数、整数、整数です)。
ファイルごとに数百バイトしかないのに、ブロックはファイルごとに1つです。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で同じ2つのファイルを実行した出力4行を、/root/hdp/blocks/checksum.txtに保存してください。
デフォルトのファイルチェックサムは「チャンクCRCのMD5のMD5」なので、ブロックの境界が結果に混ざり込みます。内容が同じでもブロックサイズが違えば値が違い、そのため、ブロックサイズが異なるクラスター間でdistcpの検証が食い違います。COMPOSITE_CRCは、ブロックの境界と無関係なCRCを作るので、同じ値を出します。
ブロック・レプリケーション・チェックサムを数値で
/root/hdp/blocks/report.mdに、## 블록으로 쪼개기・## 복제・## 체크섬の3つの節を書いてください(見出しは韓国語で、順に「ブロックへの分割」「レプリケーション」「チェックサム」を意味します)。最初の節にステップ1のブロック数を、2つ目の節にステップ5のレプリケーション不足のブロック数とステップ6のブロック数を、数値で入れてください。
ブロックサイズを誰が決めるか、レプリケーション不足はいつ生じて誰が直すのか、チェックサムがなぜブロックサイズに結び付くのかを、1、2文ずつ書いてください。