TT Lab
はじめる
学ぶ 学習パス コース

Apache Hadoop — 1つのPodにHDFSとYARNを立てて運用する

消したファイルを戻す二つの道 — ゴミ箱とスナップショット

TT Labで続きを見る

一言でいうと

HDFSで削除したものを元に戻す方法は2つあります。ごみ箱は、シェルが削除する代わりに移動しておくクライアント側の仕組みで、デフォルトではオフです。スナップショットは、NameNodeがディレクトリのある時点を丸ごと保持する仕組みなので、-skipTrashで削除したものまで復元できます。その代わり、保持したブロックは、削除しても容量が戻りません。

なぜ2つの方法が必要なのか

分散ファイルシステムでは、ミスの影響が大きくなります。パスを1つ打ち間違えたrm -rが数TBを消し、間違ったジョブが昨日の結果を上書きします。ローカルディスクならバックアップから取り出せばよいのですが、HDFSのデータは、バックアップするには大きすぎることが多いです。

そのため、HDFSは、性格の異なる2つの仕組みを用意しています。1つは人間の打ち間違いを狙った軽い仕組みです。シェルで削除したファイルを、しばらく別の場所に保管します。もう1つは、ディレクトリの過去の状態そのものを残す仕組みです。誰がどんな方法で削除・上書きしても、その時点に戻れます。両者は、動作する場所も、防げる範囲も、払う代償も違います。

どう動くのか

まずごみ箱です。設計ドキュメントの領域回収の節は、ごみ箱の設定がオンなら、FSシェルで削除したファイルをすぐには消さず、ごみ箱ディレクトリに移動すると説明しています。ユーザーごとに/user/<이름>/.Trash(プレースホルダーはユーザー名です)があり、削除したばかりのファイルは、.Trash/Currentの下に元のパスのまま入ります。決められた間隔ごとにCurrentを日付名のチェックポイントに変え、有効期間が過ぎたチェックポイントは削除します。そのときに初めて、NameNodeが名前を削除し、ブロックが解放されます。

ごみ箱の有効期間は、core-default.xmlのfs.trash.intervalで、単位は分です。デフォルトは0で、0ならごみ箱がオフになります。インストールしただけで設定に手を付けていないクラスターでは、rmは即時削除です。このコースのラボのイメージは、この値を1440分、つまり1日に設定してあります。この値は、サーバー側とクライアント側のどちらにも置けますが、サーバー側がオンならサーバーの値を使い、クライアントの値は無視します。サーバー側がオフのときだけ、クライアントの設定を見ます。

ここで、この仕組みの性格が現れます。ごみ箱は、削除する代わりに移動するものであり、その判断をシェルが行います。シェルドキュメントのrmの説明も、ごみ箱がオンなら、ファイルをごみ箱ディレクトリに移動すると書いています。そのため、-skipTrashを指定するとすぐに削除され、シェルを経由せず、ファイルシステムAPIで直接削除するプログラムには、このセーフティネットがあると仮定しないほうが安全です。上書きも防げません。ごみ箱が保管するのは、「削除したファイル」だけです。

スナップショットはNameNodeが保持する

スナップショットドキュメントは、スナップショットを、ファイルシステムの読み取り専用の時点コピーと定義しています。コピーという言葉に怖気づく必要はありません。ドキュメントが挙げる実装の性質が核心です。

そのため、スナップショットはNameNodeのメタデータの仕組みです。ファイルを削除しても、スナップショットがそのブロック一覧を持っているので、ブロックは解放されません。そのため、-skipTrashで削除したファイルも復元できます。

hdfs dfsadmin -allowSnapshot /data/sales          # 관리자: 스냅샷을 허용
hdfs dfs -createSnapshot /data/sales s1           # 소유자: 한 시점을 찍는다
hdfs dfs -rm -skipTrash /data/sales/2026-09.csv   # 휴지통을 건너뛴 삭제
hdfs dfs -cp -ptopax /data/sales/.snapshot/s1/2026-09.csv /data/sales/
hdfs snapshotDiff /data/sales s1 .                # s1 과 지금의 차이

スナップショットは、.snapshotという予約済みパスの下で、名前で読みます。復元は、そのパスからコピーすることです。ドキュメントの例は、-ptopaxで、時刻・所有者・権限・ACL・拡張属性を一緒に保持します。snapshotDiffは、2つのスナップショット、またはスナップショットと現在(.)の差を、+(作成)、-(削除)、M(変更)、R(名前変更)で表示します。スナップショットディレクトリの外に移動したものは削除されたものとして、外から入ってきたものは新しく作成されたものとして出ます。

スナップショット名を指定せずに作成すると、s20130412-151029.033のように、作成した時刻で名前が付きます。どのディレクトリがスナップショット可能かはhdfs lsSnapshottableDirで、1つのディレクトリのスナップショット一覧はhdfs lsSnapshotで見ます。定期的に取るなら、名前に日付を入れておくほうが、保持ポリシーを回しやすくなります。

制約もはっきりしています。スナップショットの許可はスーパーユーザーの仕事で、作成・削除・名前変更は、そのディレクトリの所有者の仕事です。スナップショットを許可したディレクトリの祖先や子孫には、さらに許可できません(入れ子禁止)。ディレクトリ1つに同時に置けるスナップショットは65,536個で、hdfs-default.xmlのdfs.namenode.snapshot.max.limitのデフォルトも65536です。そして、スナップショットが残っているディレクトリは、削除も名前の変更もできません。スナップショットをすべて削除する必要があります。

2つの方法を並べると

ごみ箱 スナップショット
どこで クライアント(シェル)が移動する NameNodeがメタデータとして保持する
デフォルトの状態 オフ(fs.trash.intervalが0) ディレクトリごとに許可が必要
防げるもの シェルで削除したファイル 削除・上書き・名前の変更のすべて
防げないもの -skipTrash、上書き スナップショットを取る前の変更
容量 有効期間が過ぎれば解放される スナップショットを削除するまで保持する

現場での姿

1つ目は、ごみ箱がオンになっているかをまず確認することです。デフォルトが0なので、新しく作ったクラスターはたいていオフです。rmのあとに「trashに移動した」というメッセージがなかったなら、即時削除でした。

2つ目は、スナップショットが容量を保持することです。削除したファイルのブロックをスナップショットが持っているので、削除しても空き容量は増えません。シェルのドキュメントのとおり、countは-xを指定しなければ、スナップショットの中のものまで数えます。古いスナップショットを定期的に削除する保持ポリシーも、併せて必要です。

3つ目は、スナップショットの差分が、増分コピーの材料になることです。DistCpドキュメントの-diffは、-updateと一緒に使われ、2つのスナップショットの差分レポートで、コピー元とコピー先の違いを見つけて、コピー先に適用します。毎回全体を走査せず、変更されたものだけを移します。

4つ目は、スナップショットを取ってあるディレクトリは、整理するときにブロックされることです。プロジェクトが終わってディレクトリを削除しようとして失敗したら、残っているスナップショットを先に見ます。

実務で本当に大切なこと

次のラボですること

ディレクトリにスナップショットを許可して最初のスナップショットを取ったあと、普通のrmで削除したファイルがごみ箱に行くこと(このラボのイメージは、ごみ箱を1日に設定してあります)と、ごみ箱をスキップして削除したファイルを、スナップショットからコピーして復元することを、順に試します。ファイルの末尾に行を追記して2つ目のスナップショットを取り、snapshotDiffで何が変わったかを読みます。スナップショットが残っているディレクトリを丸ごと削除しようとして拒否されることを確認し、2つ目のスナップショットの名前を変えてみたあと、ごみ箱とスナップショットの違いをレポートにまとめます。