第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図の字が小さくて追いかけきれませんでした。後でじっくり見たいです。