JavaOne報告会でJavaFXについての発表&LTを行ってきました

10/19 に実施されたJavaOne 2013 サンフランシスコ報告会 Tokyoにて、JavaFXのアップデートについての発表とLTを行ってきました。

当日のJavaFXアップデートの資料は以下の通りです。

JavaOne2013報告会 JavaFX Update from Takashi Aoe

JavaOne初参加の身でありながら、例年は櫻庭さんが担当されているポジションを引き継ぐことになったので、とても緊張しました。
自分の前に寺田さん、大山さん、櫻庭さんが発表がありました。3人の発表で場が大盛り上がりした状態で自分の発表に入ったのですが、自分の発表になると雰囲気がしーんとした感じになってしまったので、「うわ、これは失敗かなあ...」とショックを受けたのですが、後から聞いた話だと結構皆さんそれなりに楽しんで聞いて頂けたようで、ほっとしています。
そうは言ってもこのような大きな場で長丁場の発表をするのにはまだまだ修行が必要だと言うことがよーく分かりました。精進します。

本編のJavaFXアップデートに続いて、LTでもお話しをしてきました。こちらはJavaOneではちょっと珍しい感じのHadoopのセッションについてです。
JavaFXの方は真面目な感じで行ったので、こちらはちょっとくだけた感じにしました。
発表資料は次の通りです。

JavaOne2013報告会 LT資料 Hadoopの話を聞いてきた from Takashi Aoe

今のところSlideShareでのページビューはLTの方がちょっと上ですね。何だかんだ言ってHadoopは注目ネタですかね。

さて、ブログの方のJavaOne報告もまだ半分ほど残っていますね。こちらも早めにアップします。(^^;;

Cloudera Manager勉強会に参加してきました

7/27に開催された第1回Cloudera勉強会に参加してきたので、その内容について軽くレポートしたいと思います。
お題はCDHの運用管理ツールである、Cloudera Manager4.0の紹介でした。Hadoopは運用周りのサポート状況がまだまだ弱い状態であり、その部分に着目したCloudera Managerには強い関心を持っていたので参加することにしました。

場所はCloudera社が入っているビル (ビュレックス京橋) の地下会議室でした。少し遅れて入室したのですが、入ったら机に飲み物とお菓子が既に沢山置いてあったりして、リラックスした雰囲気で進行していました。講師は嶋内 (id:shiumachi) さんです。

SlideShareにも上がっている以下の資料をベースに概要を解説した後に、実際に画面を動かしながらの説明になりました。
http://www.slideshare.net/Cloudera_jp/cloudera-manager4namenodeha

リラックスした雰囲気で進めていたこともあって、途中質問が沢山飛び交い、随分盛り上がりました。結局予定よりかなりオーバーしていたような。
以下、上の資料に載っていない話や質疑応答を中心にまとめます。

  • ClouderaManagerについて
    • 多数のマシンの集合体を1つのシステムとして管理するという考え方の元で作られている。
      • Hadoopでは1台のサーバーが落ちてもパーツの1つが落ちたようなものなので。
    • いわゆるインストール作業が要求されるのはサーバーのみで、エージェントはインストール後に画面から対象サーバーを選択してSSHでばらまくようになっている。
    • もちろんHadoopクラスタを構成するノードに共存させてもいいが、専用ノードにインストールすることを強く推奨する。
      • 管理DBは複数種類あり、大規模なクラスタを管理する場合は別々のノードに分けた方が良い。
  • Service and Configuration Manager (SCMについて)
    • システムの起動停止を担当する。ちゃんと依存性を見て、順番に起動や停止を行ってくれる。
    • フリー版でもほとんどの機能が使えるが、Enterprise版ではバージョン管理が行える。
      • バージョン管理というより、SCMのリビジョン管理に感覚は近い。1つ1つのアクションを戻せるようになっている。
    • クライアント設定はバージョン4からちゃんと設定を反映してくれるようになった。(3では設定ファイルの生成だけ)
      • /etc の下に設定を出す。環境変数の設定なども不要にしている。
    • 面倒なHDFS HAの設定も3ステップでOK。
    • アップグレードはパッケージのアップグレードはできないが、サービスのアップグレードはできる。
    • サーバーの設定については、GUIからの設定を、/var/scm の下に設定XMLを吐き出して利用するようになっている。
      • 動的に生成するので、設定のマスタはDBにあると考える。
    • ログの取得について、ログのデータをClouderaManagerのDBに入れるようなことはしない。DBにはログファイルのインデックスのみ入っており、都度読み込みに行く。
      • ログは時系列検索が可能になっている。
  • API
    • フリー版の全ての操作をREST API化している。
    • APIドキュメントはexampleしか載っていないw (まあ、カラム名を見れば大体分かりますが...)
  • Enterprise版
    • 個別に購入するのではなく、サブスクリプションを購入したら利用できるようになる。
    • サブスクリプション版を購入したら、Cloudera側としてはClouderaManagerを使って欲しい!
      • サポート時のやり取りがスムーズになる。
      • 例の閏秒問題の時、ClouderaManagerを使っていた顧客はそうでない顧客と比較してとても早く問題を特定できたとのこと。
    • サービスモニタ画面があり、ヘルスチェックや稼働状況がポータル画面の形式でまとまっている。
    • ホストモニタ機能もある。CPU、メモリ使用率はロードアベレージといった割と基本的な項目ではありますが。
      • 項目は今のところ決めうちで、ユーザー側でカスタマイズして追加することはできないとのこと。
    • 稼働しているコンポーネントのバージョンチェック機能がある。実はこれが結構便利で、クラスパスの設定ミスなどによるバージョン不整合なども検知できるようになる。
    • ジョブのアクティビティモニタは残念ながらMapReduce1のサポートにとどまっており、MapReduce2はまだ。
    • アクティビティモニタで面白いのは類似ジョブの比較機能。95%信頼区間から外れているかを見て、性能劣化の傾向とかをチェックすることができる。
      • 「類似」の基準はジョブ名とのこと。Hiveだとクエリを見る。
    • 面白い機能として、サポート連携機能というのがある。Clouderaのサポートに渡すための診断情報を収集して送信できる。
  • デモ
    • (Terasortを流してデモしていました。)
    • Mapのローカリティを表示するチャートがある。
    • ラックアウェアネス設定もGUIから簡単に可能!ダイアログからラック名を入力して設定できてしまう。
    • ダイアログを閉じられないことがあったり、ちょっとバグっぽい動作もw
    • Oozieも管理項目に入っているが、現状は起動停止とヘルスチェック程度しかサポートしていない。
    • Hueは2.0になって、ジョブ実行管理に徹するようになった (管理機能はClouderaManagerに譲るように)。
    • ユーザーの権限管理はまだシンプル。管理者権限と閲覧権限のみ。
    • ログ検索はクラスタ、ノードをまたがって行えるので便利!
    • レポート機能があるが、ディスク周りが中心。MapReduceのレポートは1つだけあったが、デモではいつまで待っても出力されず...。
    • Pigのぶたさんのアイコンがちょっと可愛かったようなw
  • 質疑応答とか
    • 設定をXMLから読み込んだりはできる?
      • その機能はない。GUIからの設定のみ。インポート機能があるが、これはClouderaManager自体の設定のインポート。
    • ClouderaManager自体の冗長化はできる?
      • 特にそのような機能は設けていない。普通のRDBMS冗長化対策で。現状はClouderaManagerがSPOFになっているのは認識しているので、改善を検討している。
      • SCM本体のDBが生きていれば稼働はできる。なので、サービスごとにDBは分割することを勧める。
    • Enterprise版の評価版はある?
      • 個別問い合わせでお願いします、とのことです。

このような感じでした。Hadoopの管理用ツールとして欲しいところを一通りカバーできているようで、なかなか良くできているとの感想を持ちました。GUIも結構頑張って作り込んでいる印象です。
Cloudera社のサポートの経験をうまく活かしているなと思いました。サポートが遭遇したユースケースを中心に機能を作り込んでいったという感じで、とても参考になりました。

鹿駆動勉強会でLTしてきました

4/30に開催された、鹿駆動勉強会にてLTをしてきました!
奈良の、しかも新公会堂能楽ホールでLT大会をやるという前代未聞の企画で、最初は何かの冗談かと思ったりもしましたw
何せ下の写真のような立派な場所でIT勉強会の発表をやるって言うんですよ!

実は自分は奈良育ちの人間 (生まれは千葉ですが、小さい頃から社会人1年目までは奈良に住んでいました) です。
地元奈良でこんなイベントをやるなら参加するシカない!ということで、GWの帰省に合わせて参加、発表させてもらうことになりました。
発表資料はSlideShareにアップしています。
http://www.slideshare.net/takashiaoe/shikadriven-aoe

内容はAsakusa Frameworkの特長について簡単に紹介するというものです。最初にHadoop自体の説明も少し入れています。
結局テストツールの説明の所で時間切れで銅鑼が鳴ってしまいましたが、重要なポイントは説明できたと思っています。
非常に立派な場所で、しかも100人近い人達を前に発表するので、非常に緊張しましたが、とても良い経験でした。

他の発表者の内容も実に多種多様で、とても楽しく、勉強になりました。自分みたいな飛び入り的な人も結構多かったはずなのに、進行もスムーズで素晴らしかったです。
以下、それぞれの発表内容について一言コメントを。

  • @skrbさん
    • JavaFXについての分かり易い紹介。毎回JavaFXを使って凝った発表資料を新たに書き起こしているのはすごいと思います。
  • @mike_neckさん
    • レガシーコードとの闘いのお話し。コピペコードが延々繰り返されるというgkbrな光景がw この闘いのお陰でJavaFXJavaScriptのテストツールが間に合わなかったのは残念!
  • @hakuraiさん
    • JavaFXTwitterクライアントを作ってみるというお話し。今回はJavaFXの話題が多くて嬉しかったです。時間が足りなかったのが残念でした。
  • @backpaper0さん
    • 並行プログラミングのお話し。実は丁度Java並行処理プログラミングを読んでいたところだったので、自分にはとてもタイムリーな話でした。
  • @s_kozakeさん
    • SI開発におけるアーキテクトというポジションの大切さについてのお話し。確かに昨今のSIerを取り巻く環境を考えると、このポジションの重要性は増していると思っています。
  • @Kuchitamaさん
    • 新卒1年目を振り返ってのお話し。新人を育てるために皆さんソースレビューをお願いします、というお話しでした。Twitterの発言を拝見していると、割としっかりされた感じの方という印象を持っていたので、まさかまだ社会人2年目とは思いませんでした!
  • @bash0C7さん
    • 奈良の高校時代に学んだことについてのお話し。机上デバッグのお話しがとてもためになりました。
  • @tan_go238さん
    • Java7から導入されたInvoke Dynamicのお話し。今までこれについては余り追いかけていなかったので勉強になりました。
  • @dproject21さん
  • @kiy0takaさん
  • @hakoberaさん
    • nodeについてのお話し。ブラウザでWebCAM使って顔認識のデモが素晴らしかったです。node熱いなあ。
  • @shinsukeodaさん
  • @Nakauさん
    • PHPフレームワーク、Kohanaの紹介。HMVC (Hierarchical Model View Controllerの略だそうです) という言葉は初耳でした。
  • @_funyaさん
  • @yujioramaさん
  • @irofさん
    • 勉強会の意義、特に自分がしゃべることの意義についてのお話し。まずはLTから入るのがいいよとのこと。自分が今回やったのもまさにそれですね。自分が発表することでホントに色々学べたと思っています。
  • @pocketberserkerさん
    • 何とその場でネタを挙手で選ばせるという内容!キーバリューストアを例にF#でのテスト駆動開発のお話しになりました。実はF#はあんまり良く分からないのですが、テストコードの記述内容は興味深かったです。
  • @fukai_yasさん
    • 普段使っているカバレッジツールがイマイチなので自分で作っちゃいました!というお話し。ソースやバイトコードを改変しないタイプのようで、そろそろ公開したいとのこと。ちょっと楽しみです。
  • @daiksyさん
    • この鹿駆動勉強会の開催に至るまでの経緯についてのお話。今回のこのとんでもない企画を実現にこぎ着けたのはお見事だったと思います。奈良新聞は反応なしだったんですねえ。

懇親会にも参加させてもらいました。普段はTwitterなどを通してのみの交流だった関西のエンジニアの方々と直接お話しができてとても良かったです。
様々なバックグラウンドを持つ方々 (中には「これからプログラマを目指しているんです!」なんて方もいました) と交流することができました。

最後になりましたがこのような素晴らしい場を提供して頂いた主催者の皆様には厚くお礼申し上げます。ありがとうございました!

こぼれ話

SlideShareにアップした資料ですが、半日で1200View以上を集め、まさかまさかのHot on Twitter入り。大した内容でもないのに恐縮です。
で、SlideShareから1ヶ月間限定のPro版無料クーポンをもらっちゃいました。

WEB+DB Press Vol.67に記事を書きました

WEB+DB Press Vol.67の特集3「実戦投入Hadoop」内の第3章「Hadoopでログ解析」を担当しました。

WEB+DB PRESS Vol.67

WEB+DB PRESS Vol.67

  • 作者: 川口耕介,山本和彦,おにたま,神林飛志,杵渕朋彦,中島聡,清水亮,齋藤正浩,高橋征義,ミック,みやけん,青江崇,須賀秀和,上新卓也,牧大輔,角田直行,はまちや2,大和田純,白土慧,太田昌吾,個々一番,Shawn M Moore,じゅんいち☆かとう,小野修司,WEB+DB PRESS編集部
  • 出版社/メーカー: 技術評論社
  • 発売日: 2012/02/24
  • メディア: 大型本
  • 購入: 15人 クリック: 253回
  • この商品を含むブログ (26件) を見る
雑誌に記事を書くのはこれが初めてです。興味がありましたら手にとってもらえたらと。
このエントリでは執筆のこぼれ話的なことを書きたいと思います。

取り上げた解析処理について

私が担当した第3章はログ解析を題材に、初めてHadoopに触れる人がMapReduceプログラミングの基本について学ぶことを主眼に置いています。
題材にしたログはPigのチュートリアルに付属しているexciteの検索ログです。これを選んだのには理由があります。
実はAsakusa Frameworkのサンプルにバスケット解析のサンプルがあります。これも同じくPigのチュートリアルのログを使っており、当初はこれと同じ処理を生のMapReduceで作成して、最後にAsakusaのサンプルのURLを紹介して、「見比べてみてください」と結ぶつもりでした。
が、当然のことながらそんな内容では大幅に字数オーバーをしてしまい、作成するプログラムの内容も初学者にはちょっと難しい内容になってしまい (何せセカンダリソートまで出てきましたから) 、これはボツとなりました。

API?旧API

今回掲載したコードは全て新APIで書いています。実はこれも最初は旧APIで書いてました。
Hadoopは0.20にて新しいMapReduceAPIが登場しています。ところ0.20の段階では新APIが旧APIの範囲を全てカバーしておらず、中途半端な状態です。しかもその後0.21、0.22、そしてMapReduce2.0を実装した0.23がリリースされた今でも、0.20が依然Hadoopの安定リリース版として位置づけられている状況です。先日リリースした1.0も0.20系をベースにしています。
そのため、実際の現場では未だに旧APIが主流になっています。象本でも新APIの紹介はしていますが、基本的に全て旧APIで説明しています (第2版でも同じ) 。

...なのですが、そのような事情を説明した上で「IDEで横線引かれても気にしないでね」みたいな感じで書いてしまうとやはり大幅に分量が増えてしまいました。
また、執筆途中に0.22がリリースされ、それを2.0のベースにするかも、という話を耳にし、「さすがにそろそろHadoopプロジェクトとしても0.20離れを促す方向に向かうだろう」という超楽観的自己都合的予測を立て、新APIで説明することにしちゃいましたw

Hadoop MapReduceを説明するのは大変

そして初めての人に対してHadoop MapReduceを1から説明するというのは改めて大変だと思いました。
MapReduceアルゴリズム、全体の処理の流れ、実装する必要のあるクラス、Hadoop独自のI/O、ジョブの実行方法などなど、Hello Worldレベルのことをやるにも知ってもらうことが沢山あります。
それをこの短いページにコンパクトにまとめるのが一番大変でした。でも結局特集3の中では自分の担当分が一番分量オーバーになってしまいましたが...。


人に説明をする文章を書くというのは難しいものですね。でも人に説明することで自分自身の理解も深まるとよく言われるように、この執筆を通じてHadoop MapReduceについて自分の中であやふやだったところを見直すこともできたと思っています。とても良い経験でした。

hadoopアドベントカレンダー2011 19日目 Hadoopのラック認識設定部分のソースを追いかけてみた

hadoopアドベントカレンダー2011の19日目を担当する@aoetk / id:aoe-tkです。

業務でHadoopのラック認識設定を行う必要に迫られ、そのときに調べたメモを公開したいと思います。

Hadoopはネットワークトポロジーを考慮して動くことはよく知られていることでしょう。("rack awareness" である言われることが多いです)
次のような挙動を行ったりします。

  • MapReduceのタスクをノードに配置する際、ラック間の転送よりもラック内の転送を優先させる
  • HDFSは特定のラックに偏らないような複製を行う

ただし、どのノードがどのラックに所属しているか、といった情報は外部から教えてあげる必要があります。
Hadoopはインターフェース DNSToSwitchMapping の resolve メソッドを用いてノードのネットワークロケーション情報を取得します。
この DNSToSwitchMapping のデフォルト実装が ScriptBasedMapping で、このクラスは core-site.xml の topology.script.file.name プロパティで指定されたスクリプトを、ラックのアドレスを引数として起動し、スクリプトが標準出力に出力した文字列をラックIDとして受け取ります。
ということで、ノードが所属しているラックをHadoopに教えてあげるには、スクリプトを作り、その場所を topology.script.file.name プロパティで指定しておけばよいわけです。*1

前置きが長くなりました。スクリプトを作ればよいのですが、Hadoopのドキュメントを探しても、スクリプトに求められる仕様についてはっきり説明された箇所を見つけられませんでした。特に次のような点が疑問でした。

  • スクリプトはどのタイミングで呼び出されるの?
  • スクリプトの引数は1つだけ?複数渡されるの?
  • 引数にはIPとホスト名のどっちが渡されるの?

というわけでソースを追っかけてみることにしました。参照したソースは 0.20.203 のソースです。

まず、DNSToSwitchMapping を呼び出している箇所から探してみます。次の3カ所から呼び出されていました。

  1. org.apache.hadoop.hdfs.server.namenode.FSNamesystem#initialize
  2. org.apache.hadoop.hdfs.server.namenode.FSNamesystem#resolveNetworkLocation
  3. org.apache.hadoop.mapred.JobTracker#resolveAndAddToTopology

1番はNameNodeの初期化処理から呼び出されています (呼び出し元をたどると NameNode の main 関数にたどり着きました)。NameNodeを最初に起動する際に呼び出されるのはまあ分かりますね。次のように呼び出されています。

    if (dnsToSwitchMapping instanceof CachedDNSToSwitchMapping) {
      dnsToSwitchMapping.resolve(new ArrayList<String>(hostsReader.getHosts()));
    }

dfs.hosts で設定されたホスト名をまとめて渡しているようです。(HostsFileReader#getHosts をコールしており、このメソッドは dfs.hosts で設定された情報を保持している)
CachedDNSToSwitchMapping#resolve の中がどうなっているかは後で追いかけることにしましょう。

2番はNameNodeに対して、新たにDataNodeを登録する処理の過程で呼び出されています。
そして3番ですが、JobTrackerに対して新たなTaskTrackerを登録する過程と、MapReduceジョブ実行開始時にも呼び出されていました。

以上から、最初の疑問のうち、「スクリプトはどのタイミングで呼び出されるの?」について答えが分かりました。

  • NameNodeの初期化処理
  • NameNodeに対して新たなDataNodeを登録するとき
  • JobTrackerに対して新たなTaskTrackerを登録するとき
  • MapReduce実行開始時

続いて CachedDNSToSwitchMapping#resolve について見てみます。なお、CachedDNSToSwitchMapping は ScriptBasedMapping のスーパークラスに当たります。

  public List<String> resolve(List<String> names) {
    // normalize all input names to be in the form of IP addresses
    names = NetUtils.normalizeHostNames(names);

まず、頭で NetUtils#normalizeHostNames を呼んでいます。この中でさらに normalizeHostName を呼んでいますが、その実装は次のようになっています。

  public static String normalizeHostName(String name) {
    if (Character.digit(name.charAt(0), 10) != -1) { //FIXME 
      return name;
    } else {
      try {
        InetAddress ipAddress = InetAddress.getByName(name);
        return ipAddress.getHostAddress();
      } catch (UnknownHostException e) {
        return name;
      }
    }
  }

何か "FIXME" の文字が入ってますがw 、やろうとしていることは渡された値がIPであろうがホスト名であろうが、最終的にはIPに変換して返すということです。

これで、「引数にはIPとホスト名のどっちが渡されるの?」の答えが分かりました。

  • 引数には必ずIPが渡される

さらに CachedDNSToSwitchMapping#resolve の実装を読み進めていくと次のような実装が出てきます。

    // Resolve those names
    List<String> rNames = rawMapping.resolve(unCachedHosts);

ここで名前解決をしています。ScriptBasedMapping の場合、rawMapping 変数には ScriptBasedMapping のネストクラスである RawScriptBasedMapping のインスタンスが渡されています。これの resolve メソッドを見てみましょう。

  private String runResolveCommand(List<String> args) {
    // (中略)

    while (numProcessed != args.size()) {
      int start = maxArgs * loopCount;
      List <String> cmdList = new ArrayList<String>();
      cmdList.add(scriptName);
      for (numProcessed = start; numProcessed < (start + maxArgs) && 
           numProcessed < args.size(); numProcessed++) {
        cmdList.add(args.get(numProcessed)); 
      }
      File dir = null;
      String userDir;
      if ((userDir = System.getProperty("user.dir")) != null) {
        dir = new File(userDir);
      }
      ShellCommandExecutor s = new ShellCommandExecutor(
                                   cmdList.toArray(new String[0]), dir);
      try {
        s.execute();
        allOutput.append(s.getOutput() + " ");
      // (以下略)
    }
    return allOutput.toString();
  }

ちょっと引用が長くなってしまいましたが、要はスクリプトに渡す引数が多くなりすぎないようにしつつ、一定数の引数をまとめてスクリプトに渡していることが分かります。
というわけで「スクリプトの引数は1つだけ?複数渡されるの?」の答えが分かりました。

いかがでしたでしょうか。Hadoopはこれだけ広く使われているにもかかわらず、どうも公式のドキュメントは情報不足のような気がします。なので、分からないことがあったらソースを見てみるのがいいのではないでしょうか。思いのほか読みやすいですよ。

明日の12/20は@fcicqさんの予定です。

*1:DNSToSwitchMapping を実装したクラスを作るという手もあります。その場合は topology.node.switch.mapping.impl プロパティで実装クラスを指定します。

第2回Asakusaソースコードリーディングに参加してきました

AsakusaSCR第弐回に参加してきましたので、そのメモをまとめました。ほとんど自分向けの内容ですが折角なので表に置いておくにします。立て続けに勉強会参加レポートのエントリになっちゃいました。

今回はAsakusaにおいて外部とのデータのやり取りを引き受けているThunderGateのお話でした。
講師はThunderGateのアーキテクチャを設計したウルシステムズの埋金さんです。UMLaut/J-XMLの開発も担当されたそうで、昔はテレメータの開発をされてたとか。あと懇親会で聞いたのですが、かつてはWebLogicの鬼だったそうな。

なぜThunderGateを作ったのか?

  • Hadoopはデータ配るところが弱いので、そこを補うのがThunderGate
  • データをどこに置く?
    • HDFS
      • 信頼性?SPOFあるね
      • バックアップリカバリのノウハウがない (復旧できる技術者いる?少なくともデータセンターのオペレータには無理...)
    • RDBMS (これを採用)
      • 高い信頼性
      • オンライン処理との併用が可能 (バッチだけで終わるシステムなどない)
        • 整合性が課題
    • KVS
      • 未知数なところが多い
  • 何が求められるのか?
    • RDBMSへの永続化
      • HDFSとやりとり
      • HDFSがおかしくなったらフォーマットしちゃう (あくまでマスタはRDBMS)
    • オンラインがあるので排他制御必要
    • RDBMSはネットワーク的にプライベートな領域で動かすが、Hadoopはそうじゃない可能性がある -> 間にFWが入ることがある
    • 処理対象のデータ量は数GBのレベル
      • この程度ならまだ大丈夫だが、数百GBレベルをどうするかが今後の課題
      • TBレベルになるとマッチしない
    • ターゲットとなるRDBMS
      • 今回はMySQLを選択
        • 検証を行い、大丈夫だと判断した
        • 性能優先でMySQL依存を許容している
          • ちなみに標準SQLJDBC APIだけを使って組んだ場合Oracleの性能が圧倒的!
    • ワークフローエンジン
      • ワークフローエンジンは必要
      • monkey magicを採用し、これありきの作りにした
      • ただし、特定のワークフローエンジンに依存はしていない
  • どんな処理してる?
    • ImporterがRDBMSからの読み取り -> HDFSに置く -> バッチ処理 -> HDFSに結果吐き出し -> ExpoterがRDBMSに戻す、という流れ
    • 途中でこけたらRecovererを実行してもとに戻す
    • HDFSやローカルファイルのCleanerも用意している

ThunderGateの中身の紹介

  • Importer
    • 処理の流れ
      1. 最初にロックの取得
      2. MySQLのselect ... info outfile filenameを使ってTSVに吐き出す
      3. sshでExtractorを起動、TSVをZIPに固めてExtractorに渡す
      4. シーケンスファイルにしてHDFSに置く
    • 思うところ
      • sshの暗号化オーバーヘッド大きい!
      • ZIPは1Gbpsでは圧縮のオーバーヘッドの方が大きかった (ので使っていない)
      • TSV -> シーケンスファイルをExtractorでやった理由はDBに負荷を掛けたくなかったからだが、余り関係なかった
      • どうせDBに負荷集中するから分散処理はしていない
  • Exporter
    • Importerの逆
    • トランザクション確保のため、一旦ワークテーブルに書き込んでいる
      • 重複データチェックも行っている
        • Exporterには業務ロジックは置かないというポリシだったが、パフォーマンスのためにこれだけは行っている (重複チェックのためだけにHadoop側にデータを持っていくわけにはいかない)
      • ワークテーブルの存在はテストドライバにとっては重しだった...
  • トランザクション
    • RDBMSのロック機構は使っていない
    • フラグを立てて排他制御 (オンライン処理はフラグが立っているものは触らない)
    • テーブルロック、レコードロック、楽観ロックもサポートしている
    • Recovererを使ってロールバック/ロールフォワードをサポート
  • ロックの実現方法
    • ジョブIDを書きこむテーブルを用意 (カラム名にmonkey magicの名前入ってる...)
    • MySQLではフラグのオンオフはレコードを一旦読み出すのでコスト高い (データがバラバラになるとランダムIOに)
      • ロック済みレコードを別テーブルにしている (ジョインのコストはそんなに気にしてない)
      • IMPORT_RECORD_LOCKテーブルを別に用意し、行ロックの対象となるテーブルを高速に読み出せるように*1
  • ロールバック、ロールフォワード
    • Recovererが実施
    • Exporterの処理が始まるまでは消せばOK
    • Exporterの処理が中途半端にこけるのが怖い

今後どのように拡張したいのか?

  • 性能が不十分
    • 現在20MB/secで、MySQLSSHといった採用技術の限界値に達しておらず、まだ改良の余地があるはず
  • Importer、Exporterがボトルネックで、やっぱり差分情報だけ扱いたい
  • DB I/Oボトルネックの解消
    • 処理の並列化
    • SSHの問題
      • 認証だけ欲しかった
      • 同一サーバで動かす、SSHの接続を並列にするとか
      • HTTPや直接Socket通信するとか
    • HDFSへの書き込み分散
      • データ圧縮はLZOがいいかも
    • Exporter
      • 逐次実行のパラレル化
      • SQLの同時実行はMySQLでは逆効果だったが、ディスク分ければ違うかも
  • キャッシュによる最適化
    • マスターデータとかを予めHadoop側に置いておく
    • どう置く?
      • シーケンスファイルを置く
      • HBase (ランダムアクセス性能高い)
    • 差分情報をどう作成するかが課題
    • トランザクションが難しい
    • キャッシュは設計が難しいので、なるべくやらない方がいい?
  • MySQLクラスタ

その他出てきた意見など

  • MySQLクラスタどのくらい現実的かな?
    • シャーディングの設計は大変
  • 問題があったときにHDFSフォーマットする理由は?
    • データ復旧がしんどい (データセンターのオペレータにさせるのはきつい)
      • ちなみに某C社にはHDFS復旧に関する問い合わせはまだ来てない!
  • RDBMSと別のデータストレージを併用するのは現実的な考えだね
  • Sqoop使わなかった最大の理由はHadoop側からDBに触れないから

ソースコードリーディング!

ソースリーディングの内容を逐一書くのも変なので (メモし切れませんし) 、ここは感想中心にまとめます。

  • 割とシンプルな作り。Importer、Exporterと役割ごとにエントリポイントを持つ独立したJavaアプリケーションとして作っている。
  • ソースコードの記述がとても丁寧!ソースだけじゃなくコメントもとても丁寧。(というかとても正直なことを書いてますw)
  • DB側のほうがセキュリティ的に厳格なので、DB側からプロセス起動するようにしている。
  • SSHの通信はどのように書いているのかな?と思ったら、コマンド叩いてました。
    • その標準出力ストリームをZipOutputStreamでラップしてZIPデータを出力
  • ワークテーブルは毎回作成している
  • ログは普通にlog4j使っていました
    • 確かAshigel CompilerではSLF4J + LogBackを使っていたような?
  • 大量のI/O処理の記述が発生するので、例によって close() を try-catch で囲む記述が大量に...。Java7のtry-with-resourcesが待ち遠しいです。
    • コメントの「握りつぶす」がバカ受けしてました

感想

ThunderGateの設計思想についての説明を聞いていて、ThunderGateは埋金さんの長年のRDBMS開発経験を通して得られた知見がフルに込められたプロダクトなんだなあ、とまず思いました。それだけに設計思想についての説明に時間を取ってくれたことはとてもありがたかったです。
また、技術的な選択においては理想と現実の天秤を上手にとっていると思いました (RDBMSの採用、トランザクション戦略、MySQL依存の許容など)。現実に適用するシステムでの要求を満たすことを第一優先に選択、でも将来的な拡張もちゃんと考慮した作りにする、という姿勢は最近自分もプロダクト開発に関わっているのでとても参考になります。

*1:ここの説明についてですが、資料のER図の字が小さくて追いかけきれませんでした。後でじっくり見たいです。