Hadoopを試してみて気づいたのが,やはり巨大ファイルに対しては効率が良いが,
若干処理が重いものを分散して行おうとすると全然ダメと言うこと.
設計思想を考えれば当たり前なんだけど,個人的には便利な分散処理システムとして使いたい.
具体的には,パラメータ設定を変えたシミュレーションを複数同時に走らせたい.
というわけで,かなり無理矢理にシミュレーションをHadoop上で走らせてみた.
やり方としては,
- シミュレーションの設定ファイルをDFS上に書き出す
- 設定ファイルを読み込んで,対応するシミュレーションを動かす
という処理をやってみた.
ちなみに,ファイル書き出しはこんな感じ
Configuration conf = new Configuration(); Path hdfsPath = new Path(filePath); FileSystem fs = hdfsPath.getFileSystem(conf); OutputStream os = fs.create(hdfsPath); //パラメータファイルは一時ファイルとして,終了と同時に削除する fs.deleteOnExit(hdfsPath); OutputStreamWriter osw = new OutputStreamWriter(os); for(String param:paramList){ osw.append(param); osw.append("\n"); } osw.flush(); os.close();
すると,
Kind | % Complete | Num Tasks | Pending | Running | Complete | Killed | Failed/Killed Task Attempts | |
---|---|---|---|---|---|---|---|---|
map | 100.00% | 1 | 0 | 0 | 1 | 0 | 0 / 0 | |
reduce | 100.00% | 1 | 0 | 0 | 1 | 0 | 0 / 0 |
こんな感じで,Mapが一つとか二つでしか起動してくれない.
これは,Hadoopがファイルを「適切な」大きさに直してしまうからである.
設定ファイルなんてたいした大きさじゃないから,どうしても2つくらいにしか分割してくれないわけだ.
というわけで,無理矢理ファイルの区切り位置を変えることで,好きな数のMapを走らせるようにしてみよう.
Configuration conf = new Configuration(); conf.setClass("ClassName", class, Scenario.class); Job job = new Job(conf, "JobName"); //入力ファイルのPathを取得する Path inputPath = new Path(inputFile.getAbsolutePath()); //対象ファイルサイズを取得 long length = inputPath.getFileSystem(conf).getFileStatus(inputPath).getLen(); //mapTaskNumは分割したいMap数.これで,1タスクあたりのファイルの区切りサイズを決定する long splitSize = length/mapTaskNum; //最大でもそのサイズ以上にはならないようにタスクを区切る FileInputFormat.setMaxInputSplitSize(job, splitSize);
これを,job実行前に行っておけばよい.
これで,任意の数でMapを起動できる.
Kind | % Complete | Num Tasks | Pending | Running | Complete | Killed | Failed/Killed Task Attempts | |
---|---|---|---|---|---|---|---|---|
map | 100.00% | 3000 | 0 | 0 | 3000 | 0 | 0 / 11 | |
reduce | 100.00% | 1 | 0 | 0 | 1 | 0 | 0 / 0 |
分散し過ぎたw