SourceReading 20101020

728 views

Published on

Hadoop 0.21.0 でShuffleの実装が気になったので、流しで読んでみた。

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
728
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

SourceReading 20101020

  1. 1. Hadoopソースコード読み会 Shuffleを読んでみる 山下 真一
  2. 2. 2 背景 ● 某案件より:「Reduce処理に時間が掛かりすぎる!」 → リソースネックではなかった → 処理ログを見るとShuffleで延々と時間が掛かる! → これが有名なShuffleのワナね! いきなり大きな壁にぶつかった2年前の秋・・・ 月日は流れ・・・ ● 2010年8月 0.21.0リリース! → ある人曰く:「Shuffleは少々手を入れたぜ!」 → おぉ!これは確認せずにはいられなゐ! といういことで、Shuffleがどうなったか読んでみた。
  3. 3. 3 前提 ● Hadoop 0.21.0 ● 対象は、Shuffle時にMap処理結果を取得する部分 ● 大まかな流れのみで詳細や異常系までは読んでいません! ● JobTrackerはlocalモードではないです! ● 読み違いは、ご容赦を!
  4. 4. 4 Shuffleへの道のり ● Hadoopの実装では、Map処理やReduce処理はTaskTrackerそのものでは なく、TaskTrackerより生成されるChildが実行 ● Child : org.apache.hadoop.mapred.Child Childは、Map処理やReduce処理を実行する (L:217) ● taskFinal.run()よりReduceTask.run()が実行 ● Hadoopでは、ReduceTask内でShuffleが処理されるの で、ReduceTask.run()を追いかける
  5. 5. 5 ReduceTask ● ReduceTask : org.apache.hadoop.mapred.ReduceTask ● ReduceTask内でShuffleインスタンス生成 (L:353) ● Shuffle : org.apache.hadoop.mapreduce.task.reduce – 0.21.0より導入されたクラス – Shuffleコンストラクタ内でShuffleScheduler, MergeManagerイン スタンスを生成 (L:88, L:92) ● Shuffleインスタンスのrun()を実行 (L:362) Combine処理は、 Spillする場合に処理される
  6. 6. 6 ShuffleScheduler ● mapLocations : Map<String, MapHost> / HashMap ● pendingHosts : Set<MapHost> / HashSet ● finishedMaps : final boolean[] ● totalMaps : final int ● remainingMaps : int ● copySucceed() : Map処理結果の取得が成功したときに実行 ● addKnownMapOutput() : Map処理結果情報(ホスト名, MapID)を追加 ● getHost() : Map処理ホスト情報取得 ● getMapForHost() : Map処理ホストで実行したMap処理情報取得 ● waitUntilDone() : Map処理結果取得の完了までwait
  7. 7. 7 MergeManager ● IntermediateMemoryToMemoryMergerスレッド ● mapreduce.reduce.merge.memtomem.enabled = trueの場合 ● InMemoryMergerスレッド ● 特定の閾値を超えた場合、MemoryMerge → Spill 実行 ● OnDiskMergerスレッド ● DiskでのMerge ● reserve() : Map処理結果取得のためのメモリ確保 ● ディスク or メモリ or null (メモリ上で扱えるがメモリを大量に使用し ている場合) ● canShufflleToMemory() : Memory or Disk ● finalMerge() : Map処理結果を全て取得した後の最後に実行
  8. 8. 8 Shuffle ● Shuffle.run()では、2種類のスレッドを生成と起動 ● EventFetcher (L:106) : Map処理の状況を確認する ● Fetcher (L:112) : Map処理結果を取得する,複数のスレッドを生成 – mapreduce.reduce.shuffle.parallel.copiesプロパティで指定 ● デフォルト5 ● 全てのMap処理が完了するまで無限ループ待ち (L:119) ● PROGRESS_FREQUENCY : 2000ミリ秒でハードコーディング
  9. 9. 9 EventFetcher – その1 ● EventFetcher.run() : 無限ループでMap処理実行状況を把握 ● getMapCompletionEvents()を呼び出し (L:66) ● ループ内でThread.sleep(SLEEP_TIME)を実行 (L:72) – SLEEP_TIME : 1000ミリ秒でハードコーディング
  10. 10. 10 EventFetcher - その2 ● EventFetcher.getMapCompletionEvents() ● Map処理結果情報を取得ののちSUCCEEDEDのものを対象にURIや MapID、ホスト名などの情報を確認 – scheduler.addKnownMapOutput()で情報保存 (L:133) – addKnownMapOutput()内では、以下の情報を保存 ● mapLocations ← Map処理を実行したホスト情報やホスト名 ● MapHost.addKnownMap() ← Map処理のTaskAttemptID ● pendingHosts ← Map処理結果を取得するためのホスト情報 – FetcherスレッドでMap処理結果を取得
  11. 11. 11 Fetcher - その1 ● Fetcher.run() : 無限ループでMap処理結果を取得 ● scheduler.getHost()にて、取得するMap処理実行ホスト情報を取得 (L:145) ● copyFromHost()で、Map処理実行ホストより結果取得 (L:149) ● scheduler.freeHost()にて、Map処理実行ホスト情報を戻す (L:152) – 一つのホストから集中して取得することを防ぐため
  12. 12. 12 Fetcher - その2 ● ShuffleScheduler.getHost() ● pendingHosts内に複数あるMap処理ホスト情報をランダムに取得 – random.nextInt – seedは、Ramdom(System.currentTimeMillis()) ● pendingHostsはHashSetであるので、順序性を持たないためfor文によ り対象のMap処理ホスト情報をpickup
  13. 13. 13 Fetcher - その3 ● copyFromHost() ● scheduler.getMapsForHost()で取得するMap処理結果を決定 (L:172) – host.getAndClearKnownMaps() で該当ホストのTaskAttemptID を全て取得、host情報が持つTaskAttemptIDは一旦clear – TaskAttemptIDリストより、結果を取得していないSUCCEEDであ るTaskAttemptIDを20個取得 (20個はハードコーディング) – 21番目以降のTaskAttemptIDは、host.addKnownMap()で戻す ● Map処理を実行したTaskTrackerにHTTPにて接続確立 – URLに20個のMapIDを渡す ● copyMapOutput()で、TaskAttemptIDに沿ったMap処理結果をメモリ 上で保存するかディスクで保存する (L:251)
  14. 14. 14 Fetcher - その4 ● copyMapOutput() : 取得したTaskAttemptIDによる結果ごとに実行 ● header情報取得 (L:282 – L:287) ● merger.reserve()でMap処理結果でメモリで保持するかディスクで保 持するか決定 (L:305) – メモリ or ディスク の判断は”パラメータ的な話題”で説明 ● reserve結果、メモリの場合shuffleToMemory()にてMap処理結果をメ モリで保持 (L:319), ディスクの場合shuffleToDisk()にてMap処理結果 をローカルディスクに書き出す (L:322) ● scheduler.copySucceeded()で、取得完了に関して処理 (L:322) – output.commit()で、メモリ/ディスクで保持するMap処理結果数が 閾値を超えた場合、Spill/Mergeを実行 – 閾値については”パラメータ的な話題”で説明
  15. 15. 15 ポイント ● 新規Map処理結果は、EventFetcher.getMapCompetionEvents()の呼び出 しで確認できる ● 1回の取得ごとに1秒sleepする (L:72) – SLEEP_TIMEはハードコーディングされている ● Shuffle.run()内のscheduler.waitUntilDone()で状況を判断する ● 1回の確認で2秒waitする (L:364) – wait時間はハードコーディングされている ● 0.20系までと比べるとShuffleによる待ち時間は改善されている
  16. 16. 16 パラメータ的な話題 - その1 ● Fetcherにて、Map処理結果をメモリ or ディスクに書き出す基準 ● MergeManager.canShuffleToMemory() – “Reduce用ヒープサイズ * Copy用領域 * 0.25” よりMap処理結果 (1つ) が小さければメモリ – Copy用領域 : mapreduce.reduce.shuffle.input.buffer.percent ● デフォルト 0.9 ● Map処理結果をcommitするときのメモリ上からSpillする基準 ● MergeManager.CloseInMemoryFile() – “Reduce用ヒープメモリ * Copy用領域 * X” を超えた場合Spill処理 開始 – X : mapreduce.reduce.shuffle.merge.percent ● デフォルト 0.9
  17. 17. 17 パラメータ的な話題 - その2 ● disk上のMap処理結果(segment)をmergeする基準 ● MergeManager.CloseOnDiskFile() – segment数 > (2 * X – 1) となった場合に開始 – X : mapreduce.task.io.sort.factor ● デフォルト 100 ● Fetcher用スレッド(Map処理結果同時取得)数 ● mapreduce.reduce.shuffle.parallel.copies – デフォルト 5
  18. 18. 18 終わり ご静聴ありがとうございました

×