Pig on Tez / Hive on Tez メモ

昨年9月にPig on Tezの記事を書いて半年。 Hadoopも2.6系がリリースされ、Tezも0.6がリリース。 PigもHiveも正式にTez対応となりました。

今更ですが、Pig 0.14 + Tez 0.6.0 の組み合わせで、 Pig on Tezを実行してみようとすると動かない。

ログを見ると、クライアントのTezは0.5.2、サーバのTezは0.6.0というメッセージが。 Pig側を見ると、0.14のバイナリは Tez 0.5.2 が対応バージョンとのこと。

Tez 0.6.0 で動かしたい身として、Pigをリビルドしました。

Tez 0.6.0利用向けPig 0.14.0 ビルド

  1. Pigソースコード入手

    Pigコミュニティのダウンロードページには、0.14のソースコードも入手可能。 バイナリではなく、ソースコードを入手しました。

  2. ビルド環境準備

    HadoopMavenですが、PigはAntです。Apache Antを導入します。 ビルドのJavaは、OracleJDK 7を利用。

  3. ビルド

    普通にビルドしたのでは、Tezは0.5.2が入るため、Tezのバージョンを0.6.0にします。 Hadoopも23(Hadoop2系向け)を選択します。以下のようにビルドしました。

     [sinchii@work]$ ${ANT_HOME}/bin/ant -Dhadoopversion=23 -Dtez.version=0.6.0 jar
    

  4. 確認

    この手順でビルドしたPigとHDFSに導入したTez 0.6.0を利用して、Pig Latinを実行すると、バージョン情報でTez 0.6.0の利用を確認できます。

    2015-03-07 23:37:58,275 [main] INFO  org.apache.pig.tools.pigstats.tez.TezPigScriptStats - Script Statistics:

    HadoopVersion: 2.6.0                                                                                               
       PigVersion: 0.14.0-SNAPSHOT                                                                                     
       TezVersion: 0.6.0                                                                                               
           UserId: sinchii                                                                                             
         FileName:                                                                                                     
        StartedAt: 2015-03-07 23:37:47                                                                                 
       FinishedAt: 2015-03-07 23:37:58
    

    Pigはビルドしなおしたため、0.14.0-SNAPSHOTになってしまいました。 とはいえ、これでPig 0.14.0 でもTez 0.6.0を利用できそうです。

Hive 1.0 でも Tez 0.6.0を使う

Hive 1.0 でもTez 0.6.0を利用したいので、導入を試みてみました。 Tezを既にビルド済みの場合、Hiveはリビルドしなくても動作したようです。

  1. hive-site.xml

    Hive設定ファイルに、プロパティ名"hive.execution.engine"、値"tez"を設定する。

    また、プロパティ名"tez.lib.uris"、値"HDFS上のTezファイルのフルパス(hdfs://から始まる)を設定する。(他のファイルでも良いか?)

  2. mapred-site.xml

    MapReduce設定ファイルに、プロパティ名"mapreduce.framework.name"、値"yarn-tez"を設定する。

  3. hive-env.sh

    Hive環境設定ファイルに、以下のように記載する。(${TEZ_HOME}はビルドしたtez-0.6.0.tar.gz を展開したディレクトリを指定。)

    export HIVE_CLASSPATH=${HIVE_CLASSPATH}:${TEZ_HOME}/:${TEZ_HOME}/lib/
    

この設定で動作した。

Hive on Tezの場合、処理途中の画面で進捗率がバーで表示される。

Status: Running (Executing on YARN cluster with App id application_1425734864751_0005)

--------------------------------------------------------------------------------
        VERTICES      STATUS  TOTAL  COMPLETED  RUNNING  PENDING  FAILED  KILLED
--------------------------------------------------------------------------------
Map 1 ..........   SUCCEEDED      1          1        0        0       0       0
Map 2 ..........   SUCCEEDED      1          1        0        0       0       0
--------------------------------------------------------------------------------
VERTICES: 02/02  [==========================>>] 100%  ELAPSED TIME: 6.79 s     
--------------------------------------------------------------------------------
OK

これで、Hive 1.0 でも Tez 0.6.0を利用できそうだ。

以前Tezは色々なバージョンを利用できそうと書いたような気がするが、 一体どれだけの人が、複数のバージョンを使い分けることになるのだろうか。 今日時点では、ちょっと見えない感じである。

とりあえずTezのswimlanesを動かしてみた

Pig on Tezを動かしてみたの続編。 Hadoopソースコードリーディングでも話題にありましたTezのツールであるswimlanesを動かしてみました。

swimlanesは、TezのApplicationMasterが出力したログをもとに、"どのコンテナ"で"どのような処理"が"いつ"実行していたかを可視化する仕組みです。 Hadoopソースコードリーディングもそうでしたが、Hadoop Summitでも発表者の方々が熱く語っていた内容です。

swimlanes実行に関する前提条件

YARNのログ集約機能が有効であることが必須です。ResourceManagerとNodeManagerの設定ファイルyarn-site.xmlに、以下のプロパティをtrueとして記述します。

<property>
  <name>yarn.log-aggregation-enable</name>
  <value>true</value>
</property>

設定をした後に、ResourceManagerとNodeManagerを起動します。ログ集約機能がfalse(無効)の場合は、swimlanesも利用できません。

swimlanesの所在

Tezリポジトリ内に"tez-tools"ディレクトリがあります。その中にswimlanesに関する資材が一式配置されています。

[user@dev apache-tez]$ ll -R tez-tools/
tez-tools/:
合計 4
drwxrwxr-x. 2 user user 4096  9月  6 06:45 2014 swimlanes

tez-tools/swimlanes:
合計 28
-rw-rw-r--. 1 user user 1485  9月  6 06:45 2014 README.md
-rw-rw-r--. 1 user user 8044  9月  6 06:45 2014 amlogparser.py
-rw-rw-r--. 1 user user 8551  9月  6 06:45 2014 swimlane.py
-rw-rw-r--. 1 user user  980  9月  6 06:45 2014 yarn-swimlanes.sh

この中資材のうち、yarn-swimlanes.sh を実行します。

swimlanesの実行

yarn-swimlanes.sh の引数は、TezのアプリケーションIDを指定します。 Tezを実行したアプリケーションIDを指定します。

[root@client swimlanes]# bash yarn-swimlanes.sh application_1410702156554_0001
Fetching yarn logs for application_1410702156554_0001
14/09/14 07:03:44 INFO client.RMProxy: Connecting to ResourceManager at 192.168.73.XX/192.168.73.XX:18032
14/09/14 07:03:44 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable

アプリケーションを実行すると、同じディレクトリにアプリケーションID名が含まれるSVGファイルが生成されます。

[root@client swimlanes]# ls -l
合計 64
-rw-rw-r--. 1 hadoop hadoop  1485  9月  6 06:45 2014 README.md
-rw-rw-r--. 1 hadoop hadoop  8044  9月  6 06:45 2014 amlogparser.py
-rw-r--r--. 1 root   root   13536  9月 14 06:57 2014 amlogparser.pyc
-rw-r--r--. 1 root   root   17472  9月 14 07:03 2014 application_1410702156554_0001.svg
-rw-rw-r--. 1 hadoop hadoop  8551  9月  6 06:45 2014 swimlane.py
-rwxrwxr-x. 1 hadoop hadoop   980  9月  6 06:45 2014 yarn-swimlanes.sh

このSVGファイルにアプリケーションの実行状況を可視化した結果が含まれています。 SVGファイルをPNGファイルに変換するとかは各自で実施する必要があります。

SVGファイルの展開

先日実行したPig on Tezアプリケーションの結果を可視化してみました。(※画像は横に長いです。)

f:id:sinchii:20140914231234p:plain

さすがに小さすぎるので、実際に処理を実行している部分を切り出します。

f:id:sinchii:20140914234141p:plain

コンテナIDごとに、どの時間帯にどの処理を実行していたかを人目で把握することができます。

今回はサンプルデータを実行したため、コンテナ数が少なく見栄えとしては少々不足していますが、実際に大量のデータを実行する場合は、この画面も賑やかになることでしょう。

おわりに

swimlanesは、どの処理がどの時間帯に実行していたかを人目で把握できるという点で非常に有用です。 処理の連携状況の確認だけでなく、処理のチューニングのための材料にも利用できそうです。 Pig on Tezに限らず、Tezアプリケーションであれば利用できます。

Tezアプリケーションのチューニングなどアプリケーション単位での実行状況という点で、どんどん利用したいですね。

(swimlanesは、Tezアプリケーション単位での可視化ですが、YARNクラスタのレイヤーでの可視化も重要です。JMXやApplicationTimelineを利用するだけでなく、もっと違う仕組みが必要になるかもしれませんね。

とりあえずPig on Tez を動かしてみた

9月9日のHadoopソースコードリーディングに参加してTezの現状を知ることができました。 折角のタイミングということで、Pig on Tezを動かしてみようと思いました。

PigのTez対応は次のバージョンである0.14からですが、まだリリースされていません。そのため、Tezのコードが含まれるtrunkビルドしたものを利用したいと思います。

最初に結論 : Pig on Tezは良い!

利用した環境

今回 Pig on Tezは、YARN擬似分散環境を構築しました。 それぞれのバージョンは以下の通りです。

  • Hadoop : 3.0.0-SNAPSHOT (9/12にtrunkをビルドしたもの)
  • Pig : 0.14.0-SNAPSHOT (9/12にtrunkをビルドしたもの)
  • Tez : 0.6.0-SNAPSHOT (9/12にtrunkをビルドしたもの)

Pigは、ビルドする際に"-Dhadoopversion=23"を付与することで、Hadoop2系用JARファイルが生成されます。未だに、23を指定しなければならないのですね。

Tezは、tez-distディレクトリ以下にtarballが生成されています。これを利用します。

Pig on Tez を利用するための準備

それぞれtrunkをビルドしたものの、それだけではMapReduce版のPigが動いてしまいますので、Tezで動作させるように設定します。

Hadoopの設定

とりあえず、YARN環境を構築しましょう。そして、Tezを利用するための設定として、mapred-site.xmlに以下の項目を競ってします。

  • プロパティ名 : mapreduce.framework.name
  • 値 : yarn-tez

YARN上でのMapReduceではyarnと設定しますが、Tezを使うのでyarn-tezを指定します。

Tezライブラリの配置

YARN上でのTezを動作させるために、TezライブラリをHDFS上に配置します。Tezプロジェクトに記載されているような形です。http://tez.apache.org/install.html

今回は、先にビルドしたTezライブラリを以下のようにHDFS上に配置しました。

[root@hadoop ~]# hdfs dfs -put /tmp/tez-0.6.0-SNAPSHOT.tar.gz /tez/
[root@hadoop ~]# hdfs dfs -ls /tez
Found 1 items
-rw-r--r--   3 root supergroup   33794017 2014-09-11 20:32 /tez/tez-0.6.0-SNAPSHOT.tar.gz

このTezライブラリは、Pig起動時にset文で、"tez.lib.uris"プロパティの値としてHDFSのパスを指定します。以下のような形でGruntシェルで指定します(もちろん、設定ファイルに定義しても構いません。)

grunt> set tez.lib.uris hdfs://hadoop:8020/tez/tez-0.6.0-SNAPSHOT.tar.gz

なお、異なるバージョンのTezライブラリをHDFSに格納して実行時に指定することができる点は、Tezのポイントです。

サンプルデータ

以下の2つを用意しました。

[root@hadoop ~]# cat airport.txt
1,nrt
2,hnd
3,kix
4,itm
5,IZO

と、

[root@hadoop ~]# cat flight.txt
NH23,2,4,777-200
JL117,2,4,777-200
NH25,2,4,787-8
JL119,2,4,767-300
NH27,2,4,777-200
JL121,2,4,767-200
NH31,2,4,767-300
JL125,2,4,777-200
NH33,2,4,777-200
JL127,2,4,777-200
7G23,2,3,320
7G25,2,3,320
GK207,1,3,320
AP116,1,3,320
JL3005,1,4,737-800
JL1667,2,5,767-300
JL1669,2,5,737-800

このファイルをHDFS上に格納します。

サンプルコード

今回、サンプルデータを加工するPig構文を用意します。2つのデータを結合したり、集約することをあえて意識しています。

FLIGHT = LOAD 'flight.txt' USING PigStorage(',') AS (number:chararray, from:int, to:int, equip:chararray);
AIRPORT = LOAD 'airport.txt' USING PigStorage(',') AS (id:int, name:chararray);
FILTER_FLIGHT = FILTER FLIGHT BY equip != '777-300';
FLIGHT_DATA = FOREACH FILTER_FLIGHT GENERATE SUBSTRING(number, 0, 2), number, from, to;
JOIN_DATA = JOIN FLIGHT_DATA BY from, AIRPORT BY id;
FLIGHT_DATA2 = FOREACH JOIN_DATA GENERATE $0, number, AIRPORT::name;
GROUP_DATA = GROUP FLIGHT_DATA2 BY (AIRPORT::name, $0);
COUNT_DATA = FOREACH GROUP_DATA GENERATE group, COUNT(FLIGHT_DATA2);
DUMP COUNT_DATA;

Pig on Tezの実行

Tezを利用する場合は、Pigコマンドの引数で"-x tez"を指定します。なお、"-x tez_local" でローカル上でTezにてPigを処理させるモードもあります。MapReduceの場合も"local"モードがありました。

[root@hadoop ~]# /usr/local/pig/bin/pig -x tez
14/09/12 05:55:30 INFO pig.ExecTypeProvider: Trying ExecType : LOCAL
14/09/12 05:55:30 INFO pig.ExecTypeProvider: Trying ExecType : MAPREDUCE
14/09/12 05:55:30 INFO pig.ExecTypeProvider: Trying ExecType : TEZ_LOCAL
14/09/12 05:55:30 INFO pig.ExecTypeProvider: Trying ExecType : TEZ
14/09/12 05:55:30 INFO pig.ExecTypeProvider: Picked TEZ as the ExecType
grunt>

ExecTypeでTezが設定されました。先に定義したサンプルコードを実行してみました。

2014-09-12 06:30:59,056 [main] INFO  org.apache.pig.tools.pigstats.tez.TezStats - Script Statistics:

     HadoopVersion: 3.0.0-SNAPSHOT
        PigVersion: 0.14.0-SNAPSHOT
        TezVersion: 0.5.0
            UserId: root
          FileName:
         StartedAt: 2014-09-12 06:30:45
        FinishedAt: 2014-09-12 06:30:59
          Features: HASH_JOIN,GROUP_BY,FILTER

Success!

     ApplicationId: application_1410486427098_0012
TotalLaunchedTasks: 4
     FileBytesRead: 1248
  FileBytesWritten: 2106
     HdfsBytesRead: 314
  HdfsBytesWritten: 105

Input(s):
Successfully read 17 records (284 bytes) from: "hdfs://hadoop:8020/user/root/flight.txt"
Successfully read 5 records (30 bytes) from: "hdfs://hadoop:8020/user/root/airport.txt"

Output(s):
Successfully stored 6 records (105 bytes) in: "hdfs://hadoop:8020/tmp/temp903517041/tmp403811983"

2014-09-12 06:30:59,070 [main] INFO  org.apache.hadoop.mapreduce.lib.input.FileInputFormat - Total input paths to process : 1
2014-09-12 06:30:59,070 [main] INFO  org.apache.pig.backend.hadoop.executionengine.util.MapRedUtil - Total input paths to process : 1
((hnd,7G),2)
((hnd,JL),7)
((hnd,NH),5)
((nrt,AP),1)
((nrt,GK),1)

無事、Pig on Tezでコードを実行することができました。JOINやGROUPが含まれるMapReduceジョブの場合、複数のジョブが実行されるため処理時間は結構長くなるのですが、Tezの場合15秒で完了することができました。

(MapReduceモードでも実行したのですが、40秒弱と倍程度時間がかかりました。特に2回ApplicationMasterを起動する必要があったため、その時間も影響を受けていました。)

おまけ

TezでPig Latinを実行した後、ResourceManagerのWebインタフェースを見ると、TezのApplicationMasterが起動しっぱなしであることに気が付きました。

f:id:sinchii:20140912225155p:plain

これは、TezのSession機能によるものです。何度もApplicationMasterを起動することなく1つのApplicationMasterを利用することで、処理時間を短縮させることができます。 quitでgruntシェルを終了するとSessionも終了しApplicationMasterも完了します。(詳しい仕組みは追々...)

おわりに

PigでもTezを利用して、YARN上で動作させることができました。とりあえず動かしてみて感じたPig on Tezの嬉しい点は、MRv1時に利用していたPig Latinがそのまま利用できることPig Latinをより厳密に実行できるので性能改善できることでしょうか。

新たにコードを書く必要なく、そのまま利用出来る点は非常に魅力的です。移行時の手間が省けるのは、本当に有用です。 とは言え、UDFの利用とか未確認のものがあるので、その辺りは追々調べます。

現在のHadoop 2系は、MapReduceを実行するのであれば、そこそこ動作する印象はあります。一方、Tezも強力なパーツであると思います。Pig on Tezが利用できる 0.14 系のリリースが楽しみです!

(Pig on Tezは動作した。Apache Flinkはとりあえず優先度を落とすということで。。。)

NameNodeのWebインタフェースについて

新年度も始まり、Hadoopも2.4.0がそろそろリリースということで、ちょっと記事を書いてみます。

NameNodeのWebインタフェースにアクセスしてみると、少々変わりました。 昔からNameNodeのWebインタフェースを見ていた人からすると、驚きかもしれません。

f:id:sinchii:20140402202958p:plain

これまでは、JSPベースでNameNodeのFSNamesystemなどを参照して情報を収集していました。 この仕組みが、Javascriptのテンプレートエンジン(dustjs)を用いた形式に変わっています。 関連するスクリプトを参照すると、NameNodeの"/jmx"にアクセスして、必要な情報を収集し、 HTML内に埋め込まれたパラメータにて取得情報を加工しながら表示する形になりました。

/jmx とは

Hadoopは、JettyベースでHTTPにて情報を表示する仕組みが備わっています。 例えば、ノードの設定情報を確認できる /conf (ConfServlet.class)やノードのスレッド利用状況を示す /stacks (StackServlet.class)があります。 /jmxHadoop標準で利用でき、JMXに沿ってノードの情報をJSON形式で取得することができます(JMXJsonServlet.class)。

f:id:sinchii:20140402212731p:plain

Hadoop 1系では、/metrics でノードの情報を取得していたのですが、2系では、/jmx でノードの詳細な情報を確認することになります。 (2系のNameNodeやDataNodeに至っては、何も取得できなくなっております。)

/jmxではqryパラメータで特定の情報のみを取得することが可能です。Webインタフェースでも全ての情報を取得するのではなく、 qryを利用して特定の情報のみを取得しています。

例: "http://[NameNode:port]/jmx?qry=Hadoop:service=NameNode,name=NameNodeInfo"

metrics2 との違い

Hadoop 2系にも metrics2 という仕組みで、ノードの情報をファイルやGangliaなどに出力する仕組みがあります。 metrics2は、指定した間隔ごとに更新してファイルやGangliaに出力するために利用します。 一方 jmxは、リクエストした瞬間瞬間の値を確認することになります。jmxでも定期的にリクエストすることで、 metrics2と同じようなことを実現することは可能です(自分たちで収集の仕組みは必要ですが...)。

取得できる情報の違いですが、metrics2で取得できる情報は全て/jmxで取得できます。 一方、/jmxのみで取得できる情報もあります。例えば、クラスタに組み込まれたDataNodeの状態を示す情報、 HDFSのスナップショット数に関する情報です。

HDFSファイル情報の取得

以前のWebインタフェースでは、HDFS上の情報はDataNodeのWebページにリダイレクトされて、ディレクトリや ファイルの情報を表示していました。この仕組みも変更になりました。 /jmxのケースと同様に、dustjsベースでWebHDFSを利用してHDFSのディレクトリやファイル情報を取得します。

f:id:sinchii:20140402212921p:plain

おわりに

NameNodeは、HDFSのマスターとしてHDFSの情報を管理します。 もちろんMapReduce/YARN、Sparkなどなど、様々なアプリケーションを実行するときに大変重要です。 metrics2やjmxを活用して、HDFSの状態の変化を確認しつつ運用しましょう。

<補足1> 古いWebインタフェースが良いという人は、画面下部右側にリンクが隠れています。

<補足2> 2.5.0ではスナップショットの詳細情報も同様に取得できるようになります。

<補足3> Webインタフェースの最上部の緑色がHortonworks(HadoopディストリビューションHDPを提供している企業)のコーポレートカラーのように見えるので、変更したほうが良いというような議論がJIRA上で展開されたこともあります。結局変更しないままでした。

HDFSのスナップショット

この投稿は、Hadoop Advent Calendar 2013 - Qiita [キータ] 21日目です。
今日は、HDFSのスナップショットについて書きます。

HDFSスナップショット

HDFSスナップショットは、特定の時点でのHDFSの状態を記録しておくことで、問題があった場合に容易に復旧させることができる、バックアップを容易にするという目的で、Hadoopの機能としてHadoop2.2系より提供されています。
これまでも利用者が複数のコマンド(Hadoop、OS)を組み合わせれば同じような仕組みを実現できたと思いますが、これにより統一できることがポイントです。

HDFSスナップショットの特徴

HDFSスナップショットには以下の特徴があります。

  • ユーザ単位で実行可能

    スナップショットは、特定のユーザのみが取得できるわけでなく、HDFSにアクセスできるユーザであれば誰でも取得できます。

  • ディレクトリ単位での実行

    スナップショットはディレクトリ単位で指定して取得します。

  • Read-Onlyである

    取得したスナップショットはRead-Onlyとして扱われます。スナップショットに対して書き込みはできません。

  • 65536世代までスナップショットを取得可能

    デフォルトで65536世代まで、指定したディレクトリのスナップショットを取得できます。

  • スナップショットのためのリソースの増加はメタ情報のみ

    スナップショットの状態は、NameNodeのメタ情報の操作で実現します。DataNodeで管理されているブロックをコピーするわけではありません。そのため、HDFSの容量には影響を与えません。

HDFSスナップショットの操作

それでは、HDFSスナップショットを扱ってみます。

HDFSスナップショット取得可能設定

スナップショットは、何もしない状態では取得できません。以下のようなメッセージが出力されるだけです。

[sinchii@ip-10-0-0-4 ~]$ hdfs dfs -createSnapshot sample shot1
createSnapshot: Directory is not a snapshottable directory: /user/sinchii/sample

スナップショットを取得したいディレクトリがある場合は、あらかじめHDFSスーパーユーザ(NameNodeを起動しているユーザ)が、対象のディレクトリをスナップショット取得可能ディレクトリに設定しなければなりません。

[hdfs@ip-10-0-0-4 ~]$ hdfs dfsadmin -allowSnapshot /user/sinchii/sample
Allowing snaphot on /user/sinchii/sample succeeded

なお、スナップショット取得不可ディレクトリに変更する場合は、スナップショットが無い状態で、HDFSスーパーユーザによりdisallowSnapshotコマンドを実行します。

[hdfs@ip-10-0-0-4 ~]$ hdfs dfsadmin -disallowSnapshot /user/sinchii/sample
Disallowing snaphot on /user/sinchii/sample succeeded

HDFSスナップショット取得可能ディレクトリ一覧

さまざまなディレクトリをスナップショット取得可能ディレクトリにする場合、どのディレクトリが対象か分からなくなることもあります。その場合は、"hdfs lsSnapshottableDir"コマンドを実行することで確認可能です。

[sinchii@ip-10-0-0-4 ~]$ hdfs lsSnapshottableDir
drwxr-xr-x 0 sinchii hadoop 0 2013-12-21 00:09 0 65536 /user/sinchii/sample
drwxr-xr-x 0 sinchii hadoop 0 2013-12-21 00:29 0 65536 /user/sinchii/sample2

スナップショット取得

まず、スナップショットを取得するディレクトリ(sampleディレクトリ)には、以下のデータが含まれているとします。

[sinchii@ip-10-0-0-4 ~]$ hdfs dfs -ls -R sample
-rw-r--r-- 3 sinchii hadoop 109229073 2013-12-21 00:32 sample/data1.log
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:36 sample/subdir1
-rw-r--r-- 3 sinchii hadoop 59941262 2013-12-21 00:36 sample/subdir1/data2.log
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:09 sample/subdir2

このディレクトリに対して、スナップショットを取得します。

# hdfs dfs -createSnapshot <取得ディレクトリのパス> [スナップショット名]
# スナップショット名を指定しない場合、取得した時刻を名前に含める(例: s20131221-054316.743)
[sinchii@ip-10-0-0-4 ~]$ hdfs dfs -createSnapshot sample shot1
Created snapshot /user/sinchii/sample/.snapshot/shot1

取得したスナップショットは、"<ディレクトリ>/.snapshot/[スナップショット名]" で確認できます。"hdfs dfs -ls"コマンドを実行します。

[sinchii@ip-10-0-0-4 ~]$ hdfs dfs -ls -R sample/.snapshot/shot1
-rw-r--r-- 3 sinchii hadoop 109229073 2013-12-21 00:32 sample/.snapshot/shot1/data1.log
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:36 sample/.snapshot/shot1/subdir1
-rw-r--r-- 3 sinchii hadoop 59941262 2013-12-21 00:36 sample/.snapshot/shot1/subdir1/data2.log
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:09 sample/.snapshot/shot1/subdir2

なお、".snapshot"はスナップショット専用のディレクトリです。一般の利用者がmkdirコマンドなどで作成することはできません。また、スナップショットの保存先を".snapshot"から変更することもできません。

さらに、スナップショット取得可能なディレクトリ内のサブディレクトリやファイルのみを指定してスナップショットを取得することもできません。

スナップショットの比較

スナップショットの取得ごとに対象ディレクトリのファイルやディレクトリが変化することはあります。その場合、スナップショット間で違いを確認するケースもあります。この場合は、"hdfs snapShotDiff"コマンドで確認可能です。

# hdfs snapshotDiff <スナップショット対象ディレクトリ> <スナップショット名1> <スナップショット名2>
[sinchii@ip-10-0-0-4 ~]$ hdfs snapshotDiff sample shot1 shot3
Difference between snapshot shot1 and snapshot shot3 under directory /user/sinchii/sample:
M .
+ ./messages

このdiffは、HDFS上でのINodeの状態を比較します。そのため、HDFS上のファイルを削除->同じファイルの登録のようなことを行い、ファイル名やファイルの中身が同じであったとしてもdiffコマンドでは異なると判断されます。

[sinchii@ip-10-0-0-4 ~]$ hdfs snapshotDiff sample shot3 shot4
Difference between snapshot shot3 and snapshot shot4 under directory /user/sinchii/sample:
M .
- ./messages
+ ./messages

スナップショット一覧の確認

スナップショットを何度も取得すると、いつ・いくつ取得したか分からなくなることが有ります。その場合は、"hdfs dfs -ls"コマンドで、確認します。

[sinchii@ip-10-0-0-4 ~]$ hdfs dfs -ls sample/.snapshot
Found 3 items
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:41 sample/.snapshot/shot1
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:49 sample/.snapshot/shot2
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:51 sample/.snapshot/shot3
drwxr-xr-x - sinchii hadoop 0 2013-12-21 01:05 sample/.snapshot/shot4

スナップショットの削除

特定のスナップショットを削除したい場合は、"hdfs dfs -deleteSnapshot"コマンドを実行します。例えば、"スナップショット一覧の確認"の状態からshot4を削除する場合は、以下の通りです。

# hdfs dfs -deleteSnapshot <ディレクトリ> <スナップショット名>
[sinchii@ip-10-0-0-4 ~]$ hdfs dfs -deleteSnapshot sample shot4

削除できたかどうかは、"hdfs dfs -ls"コマンドで確認します。

[sinchii@ip-10-0-0-4 ~]$ hdfs dfs -ls sample/.snapshot
Found 3 items
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:41 sample/.snapshot/shot1
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:49 sample/.snapshot/shot2
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:51 sample/.snapshot/shot3

コマンド出力結果の通り削除されていることが分かります。なお、スナップショットの削除は一つずつしか実行できません。

スナップショットからのデータの取り出し

取得したスナップショットのデータを取得したい場合は、"hdfs dfs -get"コマンドや"hdfs dfs -cp"コマンドで取得できます。例えば、以下のようにコマンドを実行します。

[sinchii@ip-10-0-0-4 ~]$ hdfs dfs -ls sample/.snapshot/shot3
Found 4 items
-rw-r--r-- 3 sinchii hadoop 109229073 2013-12-21 00:32 sample/.snapshot/shot3/data1.log
-rw-r--r-- 3 sinchii hadoop 1366 2013-12-21 00:50 sample/.snapshot/shot3/messages
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:36 sample/.snapshot/shot3/subdir1
drwxr-xr-x - sinchii hadoop 0 2013-12-21 00:09 sample/.snapshot/shot3/subdir2
[sinchii@ip-10-0-0-4 ~]$ hdfs dfs -get sample/.snapshot/shot3/messages .
[sinchii@ip-10-0-0-4 ~]$ ls -al
total 4
-rw-r--r--. 1 sinchii sinchii 1366 Dec 21 01:44 messages

スナップショットの操作に関しては以上のコマンドで実現できます。スナップショットのためのコマンドとこれまで存在したコマンドを組み合わせることで、容易に操作ができます。

HDFSスナップショットの利用シーン

HDFSスナップショットの利用シーンとしては、特に以下の場合に有効だと思います。

  • HDFS上のオペレーションミス

    HDFS上に保存している、重要なデータをオペミスによって削除することはあるとおもいます。HDFS外に同じデータがある場合でも、そのデータを再度HDFSに格納するとなると、それなりに時間を要することになります。HDFSのスナップショットを取得することで、重要なデータを消した場合でも容易に復旧させることができます。

  • HDFS上のデータのバックアップ

    データが度々変わるようなディレクトリに対してスナップショットを取得することで、任意のタイミングでのHDFSの状態を抑えておきバックアップに利用することも可能です。

その他

  • スナップショットを取得すると、対象のファイルのレプリカ数も維持される。スナップショット取得後にsetrepコマンドでレプリカ数を減らしても実際には減らない。

  • HDFS上のファイルはINodeFile、 INodeDirectoryオブジェクトで扱われるが、スナップショット対象のファイルやディレクトリは、INodeFileWithSnapshot、INodeDirectoryWithSnapshotに置き換わる。replaceXXX(XXXは任意)というメソッドで置き換えている。

おわりに

HDFSスナップショットは、作成・削除・比較といった一通りの操作は実現できるようになったといえます。今後は、distcpやHive、HBaseとの連携する仕組みの開発、一時的なファイルの除外などが機能追加される予定です。
オペミスからのリカバーやバックアップという点で利用しましょう。

明日は、@yamakatuさんです。

Hadoop2系-YARN

前の記事から1ヶ月が経過してしまいました。 今回は、Hadoop1系のMapReduce分散処理基盤の課題を解消するしくみであるYARNについて書きます。


YARNの仕組み

Hadoop1系のMapReduce処理基盤の問題については以前の記事でお伝えしたとおりです。YARNではリソース管理ジョブ管理を分離することでマスタノードで生じるオーバーヘッドを軽減するように実装されています。
特に、ジョブ管理を分離したことで、MapReduce以外の処理についてもMapReduceと同じように扱えることができるようになりました。YARNではアプリケーションを動作させるための共通的な仕組みを提供しています。この仕組みを利用してMapReduceやそれ以外の処理についても同じリソース上での動作を実現しました。

YARNを構成するノードについて説明します。

ResouceManager

分散処理を実行するために処理に利用するノードのリソースを管理するマスタノードです。Hadoop1系のJobTrackerのリソース管理部分を切り出したという位置づけです。

NodeManager

分散処理の実行を制御するスレーブノードです。Hadoop1系のTaskTracker相当の位置づけです。

ApplicationMaster

アプリケーションを制御する役割を果たします。Hadoop1系のJobTrackerのジョブ管理部分を切り出したという位置づけです。MapReduceアプリケーションは、ApplicationMasterとして動作します。 ApplicationMasterは、NodeManager上で動作します。

Container

アプリケーションを実際に実行する役割を果たします。Hadoop1系のTaskTracker上で実行するMapタスク/Reduceタスクに関するChildプロセスの位置づけです。

JobHistoryServer

厳密にはYARNのノードでは無いですが、MapReduceジョブのログや履歴を管理するためのノードです。

これらのノードの細かな仕組みは別の機会で書きたいと思います。

YARN上のアプリケーション

現在、MapReduce以外のアプリケーションをYARN上で動作させるために、様々なプロジェクトが動いています。代表的なプロジェクトとしては、以下のものがあります。

  • Apache Spark : HDFS上のデータをインメモリで分散処理させるための仕組み
  • Apache Storm : ストリーミング処理基盤 Storm on YARNとして取り組まれている
  • HOYA (HBase) : 分散カラム指向型ストアであるHBaseをYARNリソース上で動作させる仕組み
  • Giraph : グラフ処理

YARN処理基盤の発展とともに、色々なアプリケーションがYARN上で動くようになるかもしれませんね。

Hadoop1系の問題

唐突ですが、いきなりブログを始めます。
自分で調べたこと、感じたことを一つ一つ書きます。


最初の記事として、Hadoop1系(Apache Hadoop)の問題について少々書きます。
Apache Hadoopについては、http://hadoop.apache.org/ などご覧ください。

これまでのHadoop

俗に言うHadoop1系では、分散ファイルシステムであるHDFSと分散処理フレームワークMapReduceの
2つの構成要素でHadoopが構成されていました。特にMapReduceは、以下の要素があります。 * JobTracker : MapReduceジョブをタスク単位に分割、タスクを割り当てる、TaskTrackerを管理する * TaskTracker : mapタスクやreduceタスクを実行する、ハートビートをJobTrackerに送信する

TaskTrackerのmap処理を実行するmapスロットとreduce処理を実行するreduceスロットの2つのスロットを予め定義します。 MapReduceジョブは、map処理とreduce処理に分解され、設定されているスロットに割り当てて処理を実行していました。

Hadoop1系のMapReduceフレームワークの問題

この構成を数台程度の環境で利用する場合には全く問題にはなりませんが、一定数(4桁)以上のサーバでHadoopクラスタを運用する場合に色々と問題が見えてきました。

  • リソース管理とMapReduceジョブ管理をJobTrackerで扱うことによるオーバーヘッド

TaskTrackerからの定期的なハートビート通信(最短0.X秒間隔)の受信はもちろん、MapReduceジョブを実行する場合のタスク制御についてもJobTrackerは扱います。
加えて、多数のジョブを同時並行的に実行するとJobTrackerの処理が限界に達することになりました。

  • リソースを十分活用できない

TaskTrackerは事前にmapスロット数/reduceスロット数を定義してTaskTrackerを実行します。mapスロット数/reduceスロット数は利用者が直接設定します。 通常は、CPUのコア数に沿って設定し、複数ジョブを同時実行する場合にmapタスクとreduceタスクが同時に実行することを考慮するため、mapスロット数/reduceスロット数も余裕を持って設定します。
つまり、"mapスロット数 < CPUコア数"、"reduceスロット数 < CPUコア数" のような設定でしょうか。

このような場合、mapタスクしか実行しないケースでは、CPUのリソースを十分利用できないと言えます。
もちろんタスクに割り当てるメモリサイズもスロット数を意識しているため、メモリも十分利用できないでしょう。

その他にも、Apache Giraphはmapタスクのみで処理を実行する。OozieのPigジョブは、一度MapReduceジョブを実行してmapタスク内でPigスクリプトを実行する、といった特殊な実行が必要というようなことも問題としてあるようです(HadoopWorldの発表より)。

これらの問題を解決するために

性能面、機能面で見えてきた問題を解決する仕組みとして、YARNと呼ばれる仕組みが開発されてきました。
特にJobTrackerの持つリソース管理とジョブ管理の分離、スレーブサーバのリソースを活用する仕組み、汎用アプリケーションの実行といった点が新たなる仕組みです。

YARNについては次の記事で説明します。