Amazon Elastic MapReduceでHadoop Streamingする時にライブラリをrequireする方法
ちょっと元データの件数が大量にある処理をしたいという要件があって、普通に逐次処理していくと恐ろしく時間が掛かるので、「こんな時こそHadoop!」って事で、久々にHadoopをいじくっていました。
ただ、自宅サーバでやろうとすると、いくら分散処理できるとは言っても結局処理するのは物理的には1台な訳で、メモリを使い切ってスワップしまくってウンともスンとも言わなくなってしまうという、とっても悲しい状況になってしまいました。
「そんな時はAmazon先生にお願い!」って事で、Amazon Elastic MapReduceを試していたんですが、ちょっとハマってしまったところがあったので、備忘録がてら記事にしようかと思います。
Mapper/Reducer以外のファイルが使えない!
以前にAmazon Elastic MapReduceを試した時は、MapperとReducerが1ファイルだけの簡単な処理でやってみただけでした。
ただ、今回はもうちょっと処理が複雑で、Mapperから別ファイルをrequireしたり、serializeしてファイルに書き出しておいたデータを使ったりするものでした。
CLIでAmazon Elastic MapReduceを実行する場合、一番簡単な書き方で以下のような形になります。
$ elastic-mapreduce --create --stream \ --input s3n://stellaqua/mapreduce/inputs \ --output s3n://stellaqua/mapreduce/outputs \ --mapper s3n://stellaqua/mapreduce/map.php \ --reducer s3n://stellaqua/mapreduce/reduce.php
Mapper/ReducerはS3に置いたものを指定する事ができて、初期化時に勝手にS3から読み込んできてHadoopの実行ノードに転送して実行してくれます。
しかし、Mapper/Reducer以外のファイルは例えS3上に置いておいても、勝手に読み込んだりはしれくれないので、Mapperとかでrequireしようとしても、読み込む事ができません。
で、どうすればいいか途方に暮れつつ調べていたら、以下のサイトさんで解決方法を見い出す事ができました。
"--cache-archive"というオプションを使う事で、Hadoop初期化時に各ノードに転送する事ができるようです。
まずMapper/Reducer以外の、ライブラリなどのファイルを一つのディレクトリにまとめておいて、jarコマンドでアーカイブします。
$ jar cvf lib.jar -C lib/ .
Mapper/Reducerでrequireしたりする時は、相対パスで書いておきます。
<?php require 'lib/Hogeclass.php'; ?>
後はElastic MapReduceを実行する時に、"--cache-archive"オプションを使ってjarファイルを指定してやればオッケーです。
$ elastic-mapreduce --create --stream \ --input s3n://stellaqua/inputs/input.dat \ --output s3n://stellaqua/outputs \ --mapper s3n://stellaqua/map.php \ --reducer s3n://stellaqua/reduce.php \ --cache-archive s3n://stellaqua/lib.jar#lib \ --num-instances 4 \ --log-uri s3n://stellaqua/logs
ついでながら、上記では、起動インスタンス数とログ出力先の指定もしています。
うまく使えば、ローカルにPEARを展開したものをアーカイブして、Hadoop Streamingから利用するとかできそうですね。
という訳で実際にElastic MapReduce上で処理させてみたんですが、またしても問題が…。
- 処理が成功しようが失敗しようが料金が掛かる
- 1回分の料金が安いとは言え、何度も失敗しているとその分料金がかさんでいくのは微妙に痛いです…。
- どこまで処理が進んだか分かりづらい
- 一応、AWS Management Console上にデバッグコンソールというのもあってsyslogが見れるんですが、ちゃんと処理が進んでいるのかどうか微妙に分かりづらいです…。
…という事で、何回もの失敗を乗り越えてやっとまともに動くようになったので、1時間ほど動かしてみたんですが、ちゃんと処理が進んでいるのかどうかよく分からなかったので止めてしまいました。Elastic MapReduceを使いこなすには、もうちょっと研究が必要そうですね…。