S-JIS[2012-04-03] 変更履歴

Hadoop TeraSort

HadoopのサンプルのTeraSortのメモ。


概要

TeraSortは、大量データのソートを行うサンプル。
どうもHadoop以外のソートとベンチマーク(ソート速度)を競う為のものっぽい。
(データの改行コードはCRLFだし、レプリケーション数1でファイルを作るようになっている)

TeraSortを使うには、TeraGenで入力データを作る。


実行例

ここではCDH3のhadoop-examplesを擬似分散モードで実行している。

まず、TeraGenでソートの入力データを作る。

$ hadoop jar /usr/lib/hadoop/hadoop-examples.jar teragen 100 input

第1引数はデータの行数を指定する。1行は100バイト出力されるので、この例だと1万バイトのデータが作られる。(改行コードはCRLFの2バイトなので、データ文字列は1行当たり98バイト)
第2引数は出力先のディレクトリー名。
なお、MapReduceが動いてファイルが作られる。(バイト数に応じてファイルが複数出来る)

$ hadoop fs -ls input
Found 4 items
-rw-r--r--   1 hishidama supergroup          0 2012-04-03 19:58 /user/hishidama/input/_SUCCESS
drwxr-xr-x   - hishidama supergroup          0 2012-04-03 19:58 /user/hishidama/input/_logs
-rw-r--r--   1 hishidama supergroup       5000 2012-04-03 19:58 /user/hishidama/input/part-00000
-rw-r--r--   1 hishidama supergroup       5000 2012-04-03 19:58 /user/hishidama/input/part-00001

そして、TeraSortでソートを実行する。

$ hadoop jar /usr/lib/hadoop/hadoop-examples.jar terasort input output
$ hadoop fs -ls output
Found 3 items
-rw-r--r--   1 hishidama supergroup          0 2012-04-03 19:59 /user/hishidama/output/_SUCCESS
drwxr-xr-x   - hishidama supergroup          0 2012-04-03 19:59 /user/hishidama/output/_logs
-rw-r--r--   1 hishidama supergroup      10000 2012-04-03 19:59 /user/hishidama/output/part-00000

結果ファイルは1つにまとまるようだ。


ちなみに、TeraSort実行後にinputを見てみると、変なファイルが出来てる。

$ hadoop fs -ls input
Found 5 items
-rw-r--r--   1 hishidama supergroup          0 2012-04-03 19:58 /user/hishidama/input/_SUCCESS
drwxr-xr-x   - hishidama supergroup          0 2012-04-03 19:58 /user/hishidama/input/_logs
-rw-r--r--   1 hishidama supergroup        129 2012-04-03 19:59 /user/hishidama/input/_partition.lst
-rw-r--r--   1 hishidama supergroup       5000 2012-04-03 19:58 /user/hishidama/input/part-00000
-rw-r--r--   1 hishidama supergroup       5000 2012-04-03 19:58 /user/hishidama/input/part-00001

スタンドアローンモードでのエラー

ところで、スタンドアローンモードでTeraSortを実行したら、例外が発生した。

$ hadoop jar /usr/lib/hadoop/hadoop-examples.jar teragen 100 input
$ hadoop jar /usr/lib/hadoop/hadoop-examples.jar terasort input output
〜
java.lang.RuntimeException: Error in configuring object
        at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:93)
        at org.apache.hadoop.util.ReflectionUtils.setConf(ReflectionUtils.java:64)
        at org.apache.hadoop.util.ReflectionUtils.newInstance(ReflectionUtils.java:117)
        at org.apache.hadoop.mapred.MapTask$OldOutputCollector.(MapTask.java:481)
        at org.apache.hadoop.mapred.MapTask.runOldMapper(MapTask.java:391)
        at org.apache.hadoop.mapred.MapTask.run(MapTask.java:325)
        at org.apache.hadoop.mapred.LocalJobRunner$Job.run(LocalJobRunner.java:210)
Caused by: java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:616)
        at org.apache.hadoop.util.ReflectionUtils.setJobConf(ReflectionUtils.java:88)
        ... 6 more
Caused by: java.lang.IllegalArgumentException: can't read paritions file
        at org.apache.hadoop.examples.terasort.TeraSort$TotalOrderPartitioner.configure(TeraSort.java:213)
        ... 11 more
Caused by: java.io.FileNotFoundException: File _partition.lst does not exist.
        at org.apache.hadoop.fs.RawLocalFileSystem.getFileStatus(RawLocalFileSystem.java:408)
        at org.apache.hadoop.fs.FilterFileSystem.getFileStatus(FilterFileSystem.java:251)
        at org.apache.hadoop.fs.FileSystem.getLength(FileSystem.java:825)
        at org.apache.hadoop.io.SequenceFile$Reader.(SequenceFile.java:1480)
        at org.apache.hadoop.io.SequenceFile$Reader.(SequenceFile.java:1475)
        at org.apache.hadoop.examples.terasort.TeraSort$TotalOrderPartitioner.readPartitions(TeraSort.java:153)
        at org.apache.hadoop.examples.terasort.TeraSort$TotalOrderPartitioner.configure(TeraSort.java:210)
        ... 11 more

「_partition.lst」というファイルが見つからなくて落ちている。

どうもTeraSortでは、ジョブの実行に先立って_partition.lstというファイルに情報を書き出し、Hadoopの分散キャッシュの仕組みを使って各ノードへ配布し、MapTaskで読み込んでいるようだ。

試しに擬似分散環境のHDFS上に出来ていた_partiton.lstをローカルに持ってきて実行したら、ちゃんと動いた(苦笑)

$ hadoop fs -get hdfs://localhost/user/hishidama/input/_partition.lst .
$ hadoop jar /usr/lib/hadoop/hadoop-examples.jar terasort input output

_partition.lstを作って読み込んでいる箇所は、以下のようになっている。

ソース 擬似分散モードでの値 単独モードでの値
書き出し TeraSort#run() Path partitionFile = new Path(inputDir, TeraInputFormat.PARTITION_FILENAME); hdfs://ホスト/user/hishidama/
input/_partition.lst
file:/カレントディレクトリー/
input/_partition.lst
DistributedCache.addCacheFile(partitionUri, job);
読み込み TeraSort$TotalOrderPartitioner# configure() FileSystem fs = FileSystem.getLocal(job);
Path partFile = new Path(TeraInputFormat.PARTITION_FILENAME);
readPartitions(fs, partFile, job);
_partition.lst _partition.lst
FileSystem#getFileStatus() (実体はRawLocalFileSystem)    
RawLocalFileSystem#pathToFile() path = new Path(getWorkingDirectory(), path); file:/var/lib/hadoop〜/cache/mapred/〜/_parition.lst file:/カレントディレクトリー/_partition.lst

キャッシュファイルの読み込みは(キャッシュはローカルにコピーされるので)RawLocalFileSystemを使うのだが、これのワークディレクトリー(getWorkingDirectory())は、System.getProperty("user.dir")の指す場所になっている。
分散モードで動かしている場合、タスクに対してはタスク専用のJavaVMが起動されるが、その際のuser.dirは「file:/var/lib/hadoop-0.20/cache/mapred/〜」を指している。要するに、キャッシュの場所を指しているので、ちゃんとキャッシュファイルが取得できる。

しかしスタンドアローン(単独)モードの場合は書き出しと読み込みのJavaVMは同一なので、ワークディレクトリーはカレントディレクトリーのままであり、キャッシュファイルの正しい場所を指さない。そのせいで_partition.lstが見つからないという事になっている。

スタンドアローンモードでは分散キャッシュが機能しないのかなぁ…と思ったが、確かAsakusaFWは分散キャッシュを使っているが(JUnitによるテスト時に)スタンドアローンモードで動いているので、大丈夫なはず。
という事は、TeraSortの分散キャッシュのコーディングがおかしいのだろうか。


Hadoop目次へ戻る / 技術メモへ戻る
メールの送信先:ひしだま