ひしだまの変更履歴

ひしだまHPの更新履歴。
主にTRPGリプレイの元ネタ集、プログラミング技術メモと自作ソフト、好きなゲームや音楽です。

AsakusaFW0.6.2 小さなジョブを速く!

2014-06-08 15:06:01 | PG(分散処理)

2014/5/22にAsakusa Framework0.6.2が出ていて、ブログを書こうと思っていたのに、忙しくて延び延びになってた^^;
リリースノート
(ちなみに忙しくてもDQ10の日課はやってるよ、あれは精神安定剤のようなものだから、むしろやらねばならんw)

今回は主に運用環境(実行時の設定)周りの機能が増えている。


まず注目したいのは、「小さなジョブ」に関する最適化。

Asakusaアプリケーションの場合、複数のファイルを結合したりするので、少量多種のファイルを扱うことがよく出てくる。これはHadoopの本来の使途からすると外れていて、Hadoopの苦手とするところorz
入力データサイズが小さい(理想的にはすぐ終了するはずの)ジョブであっても、Hadoopのタスク起動にはそれなりの時間(いわゆるHadoop税)がかかるので、遅い。
特にタスクは分散しているのだけれどもそれぞれのタスクの出力量は少ない場合、小さいファイル(最悪の場合は0バイトのファイル)が大量に出来てしまう。後続ジョブではファイル数(ブロック数)分のMapタスクが作られるので、無駄な時間の累計が増えてしまう。
そこで、1つのMapタスクで複数のファイル(入力スプリット)を読むようにすれば、総体としてHadoop税が減る。→入力スプリットの結合
また、Reduceタスク数を減らせば、出力ファイル数(後続ジョブに渡るファイル(スプリット)数)も減らせる(1タスクが1ファイル出力するので)。→Reduceタスクの調整

これらのタスク数を調節する為のオプション(ファイルサイズの閾値)が指定できるようになった。


それと、対応プラットフォームについては、Hadoop2系(CDH5)が増えてきた。

Hadoop2系にはuber mode(ユーバーモード。uberはドイツ語?)というのがあるらしく、これを使うと小さなジョブの実行をHadoop側でも速くできるらしい。

uberモードについては(象本第3版には載っているらしいが)よく知らないので以下は憶測だが。
通常のHadoop2(YARN)では、アプリケーションマスター(AM)がタスク実行用のコンテナーを起動してジョブを実行する。(JobTrackerとTaskTrackerの関係と同様で、コンテナーは別マシン上に別JavaVMを起動して動く)
ただ、条件を満たした場合(概ね、タスク数が少なくて入力データが小さくてメモリーに乗り切ること?)は、アプリケーションマスターが直接ジョブを実行する(AMと同じJavaVM上でジョブを動作させる)ことによって、コンテナー起動のコストを抑えるらしい。これがuberモード。

AsakusaFWでもジョブの振り分け機能で小さなジョブをスタンドアローンHadoopに振り分けることによってHadoop税を軽減させる方策があったけど、それをHadoopが自動的に実施してくれる感じかな?

つまり、AsakusaFWの「小さなジョブの最適化」とuberモードが組み合わさると、いい感じになるかも?!


あとは、YAESSログの可視化ツール!

Asakusaアプリケーションは複数のHadoopジョブに分かれるので、実行時間を解析するときは、ジョブ毎の実行時間を調べるのが最初のステップ。
その為にYAESSログからジョブの開始と終了の行を抽出して…ということをよくやっていたのだけれど、それをやってcsvファイルにして出力してくれるらしい!
gradlewコマンドを使うということは、実行環境で出力されたYAESSログを開発環境にコピーしてくる必要はある。
レポートファイルの例には実行時間を表す棒グラフも付いているけど、csvファイルにそんなものが入れられるわけが無いから、これはExcelの機能でこういう事も出来るという例だろう。

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

Java8でScala不要論?

2014-06-08 11:40:10 | PG(Java)

たぶんジョークだと思うんだが「Java8があったらScalaが不要になる」みたいな事を言っている人がいて、本気だとすると、Java8もScalaも見たことないのに言ってるだけだと思う。
ということで一応マジレス?しておく(笑) 

  • Java8でインターフェースにメソッド(デフォルト実装)が持てるようになった。
    • Java8のインターフェースは可視性にpublicしか指定できないが、Scalaのトレイトはpublic以外も可。
    • Java8のインターフェースはフィールド(static finalな定数以外)を持てないが、Scalaのトレイトは持てる。
  • Java8でStreamが導入された。
    • Java8ではプリミティブ用のStreamとオブジェクト用のStreamがあり、mapもそれらに応じてmapToObjmapToInt等のメソッドがあり、使い分けなければならない。Scalaは全てmapメソッドで出来る。
    • Java8のStreamにはzipやdrop・takeWhileといったメソッドが提供されていない。
    • Java8のStreamのflatMapはStreamを返す関数しか渡せない。ScalaのflatMapはListでも配列でもOK。
    • Java8のStreamは、Listに変換するにはcollectメソッド(Collectors.toList)を使う。ScalaはtoListというメソッドを使う(メソッド名が分かり易いし短い)。
    • Java8ではStream以外のコレクションにはmapやfilterといったメソッドは追加されていない。ScalaではStream以外のコレクションにもある。
  • ラムダ式
    • Java8では変数名が外部スコープと同じになる(ラムダ式の引数に外部と重複した変数名が使えないのは痛い)。
    • Java8ではラムダ式の本体から外部スコープの変数にアクセスする場合はその変数がfinalである必要がある。Scalaでは外部スコープの変数の値も書き換えられる。
    • Java8では複数の文を書いたらreturnを書く必要がある。
    • Scalaにはプレースホルダーがある。
  • Optional
    • Java8のOptionalは、ScalaのOptionとほぼ遜色ないかな。
    • Java8では(Streamと同様に)プリミティブ用のOptionalIntとかがあって、オブジェクト用のOptionalと相互変換できないのが不便だけど。
  • メソッド参照
    • Scalaでもメソッドを関数として渡すことは出来るが、見た目は(通常のメソッド呼び出しなのか関数オブジェクトを渡しているのかは)分かりにくいかもしれない。
  • コンストラクター参照

Streamのメソッドが足りない件については、最初は最小限にして、後から追加していくつもりなんじゃないかと思う。(最初から多すぎてもどれを使えばいいのか迷うだけだし^^;)

Stream以外のコレクションにmapやfilterといったメソッドが無いのは、実行性能や理念の問題で敢えて入れていないのだろう。
(例えばListの場合は、もしmapが即時評価だったらmapを複数チェーンすると実行速度が遅くなる。そうなっていたらStreamを介すのが解決策になるわけで、結局Stream以外のmapは使われなくなるだろう)
(例えばListのメソッドは自分自身を操作するので、filterの代わりにremoveIfといったメソッドが加わっていたりする。(filterは、値をフィルタリングした新しい集合を返す。removeIfは、指定された条件で自分自身の中から削除する))

そういや、int用のStreamはIntStreamなのに、int用のOptionalがOptionalInt(「Int」の付く位置が違う)なのは何故だ?^^; 


Javaは、バージョン間の上位互換を非常に重視している。(以前のバージョンで書いたソースやコンパイルしたクラスがそのまま新バージョンで動作することを目指している)
その制約の中では、上記に挙げた欠点も、妥当な選択の産物だとは思う。

プリミティブ用のStreamを用意したり、mapToIntやmapToObjによってStreamの種類を変換したりするのも、よく考えたなぁと感心する。
でも使う側からすると、Scalaより面倒なことに変わりはない(苦笑)

コメント
  • X
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする