LoginSignup
9
12

More than 5 years have passed since last update.

HDFS SnapshotsとDistCpを利用したHDFSデータの差分更新

Last updated at Posted at 2016-04-08

Cloudera Engineering BlogにてCDH5.5にDistCpの高速化が実装されたと紹介されていたので、試してみました。

リンク先の説明を読んだ限り、2つのHDFS Snapshot間の差分情報を使って

  • 削除・名前変更はDistCpを使わずに反映
  • 新規作成・変更されたファイルだけをDistCpで同期

することで、高速化を図っているようです。

試した環境は、

  • CentOS: 7.2 (64bit)
  • CDH 5.7.0 (擬似分散)

です。

HDFSの準備

今回は、

  • 同期元ディレクトリ:/user/hadoop/source
  • 同期先ディレクトリ:/user/hadoop/target

という状況とします。

[hadoop@localhost ~]$ hdfs dfs -mkdir source
[hadoop@localhost ~]$ hdfs dfs -mkdir target
[hadoop@localhost ~]$ hdfs dfs -ls
Found 2 items
drwxr-xr-x   - hadoop supergroup          0 2016-04-08 21:25 source
drwxr-xr-x   - hadoop supergroup          0 2016-04-08 21:25 target

sourceディレクトリには適当なファイルを入れておきます。

[hadoop@localhost ~]$ echo foobar > Data.txt
[hadoop@localhost ~]$ hdfs dfs -put Data.txt source
[hadoop@localhost ~]$ hdfs dfs -ls source
Found 1 items
-rw-r--r--   1 hadoop supergroup          7 2016-04-08 21:26 source/Data.txt

両方のディレクトリをスナップショット取得可能にしておきます。
hdfs dfsadminコマンドの-allowSnapshotオプションで設定します。

[root@localhost ~]# sudo -u hdfs hdfs dfsadmin -allowSnapshot /user/hadoop/source
Allowing snaphot on /user/hadoop/source succeeded
[root@localhost ~]# sudo -u hdfs hdfs dfsadmin -allowSnapshot /user/hadoop/target
Allowing snaphot on /user/hadoop/target succeeded

スナップショット可能になっていることを確認します。
hdfs lsSnapshottableDirコマンドで確認できます。

[hadoop@localhost ~]$ hdfs lsSnapshottableDir
drwxr-xr-x 0 hadoop supergroup 0 2016-04-08 21:26 0 65536 /user/hadoop/source
drwxr-xr-x 0 hadoop supergroup 0 2016-04-08 21:25 0 65536 /user/hadoop/target

HDFS SnapshotとDistCpによる差分更新の手順

同期元ディレクトリのスナップショットを取得

スナップショット名はs1とします。
取得にはhdfs dfsコマンドの-createSnapshotオプションを利用します。

[hadoop@localhost ~]$ hdfs dfs -createSnapshot source s1
Created snapshot /user/hadoop/source/.snapshot/s1

取得したスナップショットは対象ディレクトリの.snapshotディレクトリ下に論理的に配置されるためhdfs dfs -lsで確認できます。

[hadoop@localhost ~]$ hdfs dfs -ls source/.snapshot
Found 1 items
drwxr-xr-x   - hadoop supergroup          0 2016-04-08 21:29 source/.snapshot/s1

DistCpにてスナップショット状態の同期元ディレクトリを同期先にコピー

[hadoop@localhost ~]$ hadoop distcp -update source/.snapshot/s1 target

同期が取れたことを確認します。

[hadoop@localhost ~]$ hdfs dfs -ls target
Found 1 items
-rw-r--r--   1 hadoop supergroup          7 2016-04-08 21:32 target/Data.txt

同期先ディレクトリのスナップショットを取得

distcpのベースにしたスナップショットと同名のs1で取得します。

[hadoop@localhost ~]$ hdfs dfs -createSnapshot target s1
Created snapshot /user/hadoop/target/.snapshot/s1
[hadoop@localhost ~]$ hdfs dfs -ls target/.snapshot
Found 1 items
drwxr-xr-x   - hadoop supergroup          0 2016-04-08 21:33 target/.snapshot/s1

同期元ディレクトリの情報を更新

新しくファイルを追加します。

[hadoop@localhost ~]$ echo hogehoge > Data2.txt
[hadoop@localhost ~]$ hdfs dfs -put Data2.txt source
[hadoop@localhost ~]$ hdfs dfs -ls source
Found 2 items
-rw-r--r--   1 hadoop supergroup          7 2016-04-08 21:26 source/Data.txt
-rw-r--r--   1 hadoop supergroup          9 2016-04-08 21:34 source/Data2.txt

同期元ディレクトリのスナップショットを取得

今度はs2という名前にします。

[hadoop@localhost ~]$ hdfs dfs -createSnapshot source s2
Created snapshot /user/hadoop/source/.snapshot/s2
[hadoop@localhost ~]$ hdfs dfs -ls source/.snapshot
Found 2 items
drwxr-xr-x   - hadoop supergroup          0 2016-04-08 21:29 source/.snapshot/s1
drwxr-xr-x   - hadoop supergroup          0 2016-04-08 21:35 source/.snapshot/s2

スナップショット間の差分情報を確認しておきます。

[hadoop@localhost ~]$ hdfs snapshotDiff source s1 s2
Difference between snapshot s1 and snapshot s2 under directory /user/hadoop/source:
M   .
+   ./Data2.txt

確かにData2.txtが追加(「+」で表現されます)されていますね。

DistCpで差分更新

sourceディレクトリの2つのスナップショットs1, s2の差分情報を使って、targetディレクトリにデータを差分更新します。

コマンドの引数は例によってHadoopのドキュメントではさっぱりわからないのですが、Clouderaのブロクの情報より

$ hadoop distcp -update -diff <snapshotName1> <snapshotName2> <sourceDir> <targetDir>

とのこと。
今回だと、以下のようになります。

[hadoop@localhost ~]$ hadoop distcp -update -diff s1 s2 /user/hadoop/source /user/hadoop/target
[hadoop@localhost ~]$ hdfs dfs -ls target
Found 2 items
-rw-r--r--   1 hadoop supergroup          7 2016-04-08 21:32 target/Data.txt
-rw-r--r--   1 hadoop supergroup          9 2016-04-08 23:08 target/Data2.txt

ハマりどころ

distcp -diffの際に同期元と同期先のディレクトリのパスを相対パスで指定すると、以下のようなエラーになりました。

[hadoop@localhost ~]$ hadoop distcp -update -diff s1 s2 source target
16/04/08 21:37:14 INFO tools.DistCp: Input Options: DistCpOptions{atomicCommit=false, syncFolder=true, deleteMissing=false, ignoreFailures=false, maxMaps=20, sslConfigurationFile='null', copyStrategy='uniformsize', sourceFileListing=null, sourcePaths=[source], targetPath=target, targetPathExists=true, preserveRawXattrs=false, filtersFile='null'}
16/04/08 21:37:14 INFO client.RMProxy: Connecting to ResourceManager at /0.0.0.0:8032
16/04/08 21:37:15 ERROR tools.DistCp: Exception encountered 
java.lang.IllegalArgumentException: java.net.URISyntaxException: Relative path in absolute URI: hdfs://localhost:8020./source/.snapshot/s2
    at org.apache.hadoop.fs.Path.initialize(Path.java:206)
    at org.apache.hadoop.fs.Path.<init>(Path.java:197)
    at org.apache.hadoop.tools.SimpleCopyListing.getPathWithSchemeAndAuthority(SimpleCopyListing.java:193)
    at org.apache.hadoop.tools.SimpleCopyListing.addToFileListing(SimpleCopyListing.java:202)
    at org.apache.hadoop.tools.SimpleCopyListing.doBuildListingWithSnapshotDiff(SimpleCopyListing.java:243)
    at org.apache.hadoop.tools.SimpleCopyListing.doBuildListing(SimpleCopyListing.java:172)
    at org.apache.hadoop.tools.CopyListing.buildListing(CopyListing.java:86)
    at org.apache.hadoop.tools.DistCp.createInputFileListingWithDiff(DistCp.java:388)
    at org.apache.hadoop.tools.DistCp.execute(DistCp.java:164)
    at org.apache.hadoop.tools.DistCp.run(DistCp.java:123)
    at org.apache.hadoop.util.ToolRunner.run(ToolRunner.java:70)
    at org.apache.hadoop.tools.DistCp.main(DistCp.java:436)
Caused by: java.net.URISyntaxException: Relative path in absolute URI: hdfs://localhost:8020./source/.snapshot/s2
    at java.net.URI.checkPath(URI.java:1823)
    at java.net.URI.<init>(URI.java:745)
    at org.apache.hadoop.fs.Path.initialize(Path.java:203)
    ... 11 more

どうも同期元のパスとして絶対パスを期待しているようなので、ここは素直に従います。

なお、この事象はHDFS-10216に報告されていました。
distcp -diff relative path exception
https://issues.apache.org/jira/browse/HDFS-10216

同期先ディレクトリの状態をスナップショットで保存

差分更新した状態のスナップショットs2として取得しておきます。

[hadoop@localhost ~]$ hdfs dfs -createSnapshot target s2
Created snapshot /user/hadoop/target/.snapshot/s2
[hadoop@localhost ~]$ hdfs dfs -ls target/.snapshot
Found 2 items
drwxr-xr-x   - hadoop supergroup          0 2016-04-08 22:29 target/.snapshot/s1
drwxr-xr-x   - hadoop supergroup          0 2016-04-08 23:10 target/.snapshot/s2

後はこれを繰り返すだけ。

感想

DistCpの際に全データを対象としなくなるので、DistCpを定期的に実行する際にはかなり便利だと思われます。

ブロクに書かれているように、スナップショットの差分情報から更新すべき情報に変換するロジックはそれなりに大変そうです。HDFSはファイルのUPDATEができないという制約があるのがせめてもの救いかもしれません。

しかし、HDFS Snapshotのコマンドの統一性の無さはどうにかしてほしいわ・・・

以上!

9
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
12