今日はとある私的なプロジェクトで画像の情報操作が必要になったので、ローカルで計算してもいいんだけど今後もパラメータチューニングで何度か発生しそうなので、AmazonのMapReduceを使ってみました。
今回の構成図はこんなかんじ。全部Amazonで全部PHPでやってみた。
やろうとおもったきっかけ
別に5万枚くらいじゃ実はAmazonじゃなくてもよかったりします。一晩ペチぺーのスクリプトを4〜5本平行で走らせておけば、ローカルのMySQLに結果をためるくらい可能です。でも、
- 今後のために勉強したかった。MapReduceで調べても、Apacheのログとかテキスト操作くらいしか見つからなかったので。
- データをオンラインに置きたかった・ローカルに置きたくなかった。
- そうすると、MapReduceするにせよしないにせよS3がよさそうだった。
- じゃあ、EC2一晩動かすより、MapReduceで一気にやった方が安く上がるんじゃない?とも思った。
まず処理対象の画像ファイルをS3に配備する。
Amazon MapReduceから一斉にアクセスするには、通常のレン鯖だとご迷惑をおかけするかもしれないので、S3にしました。というか最初っからS3に置くつもりでした。異なるURL体系のデータ5万ファイルをちまちまS3にアップします。最初はGUIでやろうと思ったけど、S3Foxだと1ディレクトリ内のファイルが巨大になると固まって使い物にならず、s3sync.rbを使ってみたらメタデータが書き込まれずブラウザアクセスで使い物にならず、おとなしくPHPでバッチをかきました。
- 参考:PHPからAmazon S3を利用するライブラリを3つ試してみた(うち一つは動作不可) : akiyan.com
- このライブラリ:amazon-s3-php-class - Standalone Amazon S3 REST implementation for PHP 5 - Google Project Hosting
で、5万ファイルを5スレッドくらいでちまちまアップしました。フォルダ数も含めると全部で20万強のノード数なんですが、S3はフォルダという概念がないので、PUTはファイルの数だけですみました。またそのアップロードの過程で、URL一覧をログに出力しておきます(あとで使う)。
MapReduceに必要なファイルをアップする
次に、MapReduceに必要なmapperとreducerをアップします。これはS3Foxを使いました。アクセス権(ACL)は自分のみでOKです。また、先ほどのアップロード処理で生成したURL一覧
https://s3.amazonaws.com/(略)/0001.png
https://s3.amazonaws.com/(略)/0002.png
https://s3.amazonaws.com/(略)/0003.png
https://s3.amazonaws.com/(略)/0004.png
みたいな5万行くらいのテキストファイルも/bucket_name/input/filelist.txtに配備します。
MapperとReducerの処理内容
Reducerは、よくあるテキストカウントとおなじで、Mapからの計算結果を出力して、分布をみるのに使おうと思ったので、こちらのサンプルコードをそのまま使わせていただきました。
Mapperなんですが、コピペすると長くなりますので概要をかきますと
- ログ出力toSimpleDB
- while(標準出力が存在する間)
- 巨大なテキストファイルの1行を取得=URLをゲット
- file_get_contentsして、imagecreatefromstringする。
- 画像処理を行う(GDとか普通に使える)
- 画像の処理結果を、SimpleDBにinsert(Put Attribute)する。
- Reducerに渡すタブ区切りのkey valueをechoで出力する
という感じです。PHPを1ファイルでつくらないといけないので、各ライブラリからメソッドを寄せ集めて再構成してつくりました。
SimpleDBの活用
こちらも勉強用途の色が強いのですが、最近はやりのkey/valueストアを使ってみたかった。GAE/Jは触りましたが、「負荷が上がってもリニアにスケールする」PHPから使えるKVSでメジャーで簡単に試せるもの。。。となるとSimpleDBが一番よさそうだったので、自分でサンプルコードのWebUIラッパーをかきつつ、今回のMapperにも組み込んでみました。
SimpleDBの概要はこのへんがわかりやすいです。
んで、自前でつくったWebUIラッパーがこんなかんじ。自分用なのでユルい作りです。まだRDBMSにおけるUPDATEとページ送りが未実装。
テーブル(ドメイン)のメタデータもこんな感じで日本語表示
で、結果は失敗しました。
なんか、よくわからないんですが、おそらくreducer.phpのメモリ不足か何かで2.8万ファイルくらいで止まってしまいました。それ以外にも、6400ファイルくらいで急に進捗が止まったりしたので、何か問題が起きているようでした。ログが見にくいのが難点ですね。このへんはHadoopの知識が必要なようです。timestampというvalueが複数putされている例もあったので、もうちょっと詳細にログをとりながらやってみようと思います。
ログはファイルに出力できないので、SimpleDBにputするというやり方は悪くないなと思いました。auto_incrementみたいなのがなかったはずなので、一意キーのつけ方だけが課題です。ログならマイクロ秒とかでもいいんですけどね。