バッチ高速化のあゆみ

458 views

Published on

バッチ高速化のあゆみ

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

No Downloads
Views
Total views
458
On SlideShare
0
From Embeds
0
Number of Embeds
133
Actions
Shares
0
Downloads
19
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide
  • インデックスが効いている検索
  • 効いていない
  • バッチ高速化のあゆみ

    1. 1. バッチ高速化のあゆみ 株式会社ビズリーチ 阪本 康裕
    2. 2. 1章 「はじめに」
    3. 3. 今日のお題 システム運営で必ずつきまとうバッチ処理 の長時間化。 今回はこの課題をを解決するまでに実施し た数々の施策についての紹介 各施策については施策内容と発生し得るリ スクと共に紹介。
    4. 4. 目次 1章 「はじめに」 1. 今日のお題 2. 目次 3. 自己紹介 2章 「高速化のあゆみ」 1. 対象 2. 課題 3. 施策 a. ロジック b. データソース c. インフラ 3章 「奥の手」 1. マルチプロセス化 4章 「さいごに」 1. 最終的な成果
    5. 5. 2章 「高速化のあゆみ」
    6. 6. 1. 対象(1/3) 環境/ミドルウェア ・Batchサーバ 言語:Java(Spring+Struts.Quartz scheduler) アプリケーションコンテナ:Tomcat データソース:RDS(AmazonWebService,MySQL互換) その他:検索サーバ Apache Solr
    7. 7. 1. 対象 (2/3) 対象機能 スカウトメール配信 予め企業が設定しているスカウト条件にマッチする求職者に向けてメールを配信する機能。 自動で求職者に毎日朝・夕の2回、数求人を配信している。 大まかな処理としては ①マッチング処理 ➜ 企業が出している求人と利用者の職務経歴書をマッチングし、マッチ度を算出(毎日) ②メール配信処理 ➜ 求職者に対しては毎日数件、マッチ度の高い順にスカウトメールを自動配信 の2部構成。(いずれもバッチ処理) 今回はその前者の①マッチング処理
    8. 8. 1. 対象 (2/3) マッチング処理 1. 求人のスカウト条件に一致する求職者を検索する 2. 一致したものに対してマッチ度を計算 3. 求人⇔求職者情報を格納
    9. 9. 2. 課題(1/3) バッチ処理時間の長期化 求職者200,000名☓求人70,000件の条件一致検索を行うので、純粋に処理量が多い 多数☓多数をイメージできるような、掛け算のようなイメージがあれば 求職者 ☓ 200,000名 求人 ☓ 70,000件 14,000,000,000通り
    10. 10. 2. 課題(2/3) 長時間化に伴う後続バッチの追いつき バッチ処理時間長くなると、後続のメール配信処理の開始時間に間に合わなくなる。 スカウトバッチ メール配信バッチ (後続)
    11. 11. 2. 課題(3/3) 運用上の問題 バッチ時間が始まると、その処理時間中はサーバを止めることができない。 これは新規機能リリースや、非定期のサーバ再起動が可能な機会を著しく低下させるため 運用面でも不利益が出始めていた。 帰りたい・・ まだ処理中
    12. 12. 3. 施策 a.ロジック ①トランザクション回数の削減 効果:★★☆☆☆ リスク:★★☆☆☆
    13. 13. ①トランザクション回数の削減 1求人に対する求職者のマッチ度情報は最大で全求職者数分のレコードが作成されることになるため、 RDSへのINSERT発行回数も最大で14,000,000,000通り分発生することになる。 Batch(アプリケーションサーバ)からRDSへのレコード登録は ①RDSへのコネクション接続 ※接続プールを使っている場合はこのStepは発生しない ②トランザクション開始 ③INSERTクエリ発行(レコード登録) ④コミット ⑤RDSへのコネクション切断 ※接続プールを使っている場合はこのStepは発生しない という流れとなる。 その中で登録処理は③だけだが、登録に必要な段取りとして①②④⑤が存在する。 ①②④⑤が属に言う「オーバーヘッド」となる。
    14. 14. ①トランザクション回数の削減 このオーバーヘッドは必ずしも1レコード登録する為に必要なものではなく、 複数レコードを一括で登録する際にも同じオーバーヘッドの時間で賄う事ができる。 つまり、③のステップで複数のレコードを登録することでオーバーヘッド分の時間短縮に繋がる。 イメージ 1トラン1レコード ☓ 1000件 (①〜⑤)☓1000件 = 500000ms(500秒) 1トラン1000レコード (①〜②)+③☓1000件+(④〜⑤) = 100400ms(100.4秒) ※但し、④はレコード件数増加により処理時間は増加する ①RDSへのコネクション接続 ➜ 100ms ②トランザクション開始 ➜ 100ms ③INSERTクエリ発行(レコード登録) ➜ 100ms ④コミット ➜ 100ms ⑤RDSへのコネクション切断 ➜ 100ms 約⅕に短縮(※)
    15. 15. ①トランザクション回数の削減 リスク トランザクションに登録をまとめる実装は比較的容易。 エラー時はトランザクション内の全てのレコード更新がロールバックされるため、 他レコードへの影響を考慮する必要がある。(全滅はOKか?一部更新はOKか?) 前項にも記載したが、トランザクション内で登録するレコード数が多くなればコミット処理時間も 増大する。 このコミット処理についてはRDSへの負荷に直結するので、RDSの性能と相談して件数を決める必要あ り
    16. 16. 3. 施策 a.ロジック ②処理のマルチスレッド化 効果:★★★★☆ リスク:★★★★☆
    17. 17. ②処理のマルチスレッド化 バッチの処理時間の内訳を算出すると、Batchサーバの処理時間に比べて RDSへの登録処理、Solrへの検索処理が圧倒的に多い。 その上、RDSやSolrの負荷も低いといった場合はBatch、RDS、Solrのスペックを十分に引き出せていな いことになる。 この場合に有効な策としてバッチ処理のマルチスレッド化が挙げられる。 これは単一処理(スレッド)で発生していた各々の隙間時間を極力減らすことで時間の短縮に繋げる事 ができる。 そもそもRDSもSolrも複数アクセスを前提に設計されているので、単一アクセスでスペックを十分に 発揮し切ることは少ない。 Batchサーバ Batchサーバ
    18. 18. ②処理のマルチスレッド化 具体的には ①スカウト条件に一致する求職者を検索する ②一致したものに対してマッチ度を計算 ③求人⇔求職者情報を格納 だった処理を ・処理対象となる求人のリストを抽出 ・抽出した求人群をスレッド数分に分割する ・下記の処理を行う子スレッドを並列分だけ生成し、前項の分割分を渡す ・スカウト条件に一致する求職者を検索する ・一致したものに対してマッチ度を計算 ・求人⇔求職者情報を格納 ・並列分の子スレッドが全て終わるのを待機する へと変更する。
    19. 19. ②処理のマルチスレッド化 before
    20. 20. ②処理のマルチスレッド化 after この処理をスレッド化
    21. 21. ②処理のマルチスレッド化 after
    22. 22. ②処理のマルチスレッド化 マルチスレッド化に伴う子スレッドの管理。 バッチ処理本体を本スレッド、実処理を子スレッド(複数)として位置付けすると 本スレッドは全ての子スレッドの終了を監視する必要がある。 親スレッドは子スレッドの状況、特にエラーは検知し辛いので 子スレッドのエラーは自身で対処できるようにしないと行方不明になる サーバのスペック以上に分割しても返って遅くなる&誰かが負荷倒れすることになるので注意 リスク
    23. 23. 3. 施策 a.データソース ①インデックスチューニング 効果:★★★★☆ リスク:★★★★☆
    24. 24. ②インデックスのチューニング RDS(MySQL)への検索時に使用するインデックスを見直し 検索しようとしている条件に 一致したインデックスが 用意されているか? 用意されていた場合、 実際に使われているのか?
    25. 25. ②インデックスのチューニング 検索しようとしている条件に一致したインデックスが用意されている か? テーブルレイアウト 実データ
    26. 26. ②インデックスのチューニング 検索しようとしている条件に一致したインデックスが用意されている か? テーブルレイアウト 実データ IDX_1
    27. 27. ②インデックスのチューニング 検索しようとしている条件に一致したインデックスが用意されている か? テーブルレイアウト 実データ IDX_2
    28. 28. ②インデックスのチューニング 検索しようとしている条件に一致したインデックスが用意されている か? テーブルレイアウト 実データ IDX_1_2
    29. 29. ②インデックスのチューニング 検索しようとしている条件に一致したインデックスが用意されている か? テーブルレイアウト 実データ
    30. 30. ②インデックスのチューニング 検索しようとしている条件に一致したインデックスが用意されている か? テーブルレイアウト 実データ explain結果
    31. 31. ②インデックスのチューニング 検索しようとしている条件に一致したインデックスが用意されている か? テーブルレイアウト 実データ
    32. 32. ②インデックスのチューニング 検索しようとしている条件に一致したインデックスが用意されている か? テーブルレイアウト 実データ explain結果
    33. 33. ②インデックスのチューニング RDS(MySQL)への検索時に使用するインデックスを見直し インデックスの有無によりDBの検索対象レコード範囲が全景になるか否か挙動が異なる ➜ 大量のレコードがテーブルに存在するほど影響が大きくなる
    34. 34. ②インデックスのチューニング RDS(MySQL)への検索時に使用するインデックスを見直し 定義インデックスが実装で発行するクエリに添っているか? ➜ 実装の改修などでDDL変更されたケースなどでインデックスも再設計されているか?
    35. 35. コード変更を伴わない為、アプリの挙動には影響しないのがこのチューニングの強み。 但し、インデックス登録時のALTER TABLE中は対象テーブルが共有ロック(読み取り専用)になる可能性 があるので注意。 特に外部制約でリンクしている子テーブルも同様のロックが発生するので、システムの肝となるテーブ ルが対象となった場合はサービス停止もあり得るため、運用の事故は大きく発生し得る ②インデックスのチューニング リスク
    36. 36. 3. 施策 a.データソース ②クエリ(insert文)チューニング 効果:★★★☆☆ リスク:★★☆☆☆
    37. 37. ②クエリ(insert文)チューニング レコードの登録時に発行するSQLは 1レコード目:INSERT INTO ◯◯ VALUES (AA,AA,AA) 2レコード目:INSERT INTO ◯◯ VALUES (BB,BB,BB) 3レコード目:INSERT INTO ◯◯ VALUES (CC,CC,CC) ・ ・ といった形でRDSにSQLクエリを発行している。 この個々のクエリ発行にはRDSのの通信が発生するため、この通信オーバーヘッドがレコード数分 発生することになる。 例えばこのオーバーヘッド時間が10msだとすると、1000件更新では10000ms(100秒)にまで膨れ上がる このクエリを INSET INTO ◯◯ VALUES (AA,AA,AA),(BB,BB,BB),・・・・・ と、1INSERT文で複数レコードを登録してしまうとこのオーバーヘッド時間(回数)の削減に繋がる
    38. 38. ②クエリ(insert文)チューニング あまりに複数登録しすぎると発行SQLを文が大きくなりすぎてデバッグが困難になる INSET INTO ◯◯ VALUES (AA,AA,AA),(BB,BB,BB),(CC,CC,CC),(DD,DD,DD),(EE,EE ,EE),(FF,FF,FF),(GG,GG,GG),(HH,HH,HH),(II,II,II),(JJ,JJ,J J),(KK,KK,KK)(LL,LL,LL)・・・・・ (LL,LL,LL)・・・・・・・・・・・・・・・・・・・・・ リスク
    39. 39. 3. 施策 a.インフラ ①RDSスケールアップ 効果:★★★★☆ リスク:★★★☆☆
    40. 40. ①RDSのスケールアップ AWSサービスの1つRDS。 こちらはインスタンスのサイズを1段階上げることにより純粋の処理スペックの向上 また、インスタンスサイズに連動してネットワーク性能も向上するので通信上の高速化も さらにストレージをマグネチック(DISK)からSSDへと変更することでIOも高速化 RDS料金/スペック
    41. 41. ①RDSのスケールアップ AWSの使用料金が増加 スケールアップ時にはRDSの再起動が必要。全システムがRDSに依存しているため 全てのサービスを停止する必要がある リスク
    42. 42. 3. 施策 a.インフラ ②Solrのクラスタリング 効果:★★★★☆ リスク:★★★☆☆
    43. 43. ②Solrのクラスタリング Solrの台数(EC2インスタンス)を増やすことで、必要な処理を分散して全体の許容量を上げる クラスタリングにはAWSのロードバランサーにて2台のSolrへとアクセス分散を実現
    44. 44. ②Solrのクラスタリング EC2インスタンスが1台(Solr分)と、EBSの料金が運用コストとして増加する データ同期が必須。 リスク
    45. 45. それでも間に合わない・・・ ・どれだけ高速化の策を打っても1バッチの処理時間を短縮するには限界がある ➜ インスタンスの性能を上げても、費用に見合う成果は出ない
    46. 46. 3章 「奥の手」
    47. 47. 4. 奥の手 マルチプロセス化 効果:★★★★★ リスク:★★★★☆
    48. 48. ②マルチプロセス化 残された課題 ➜ 1つのバッチ処理時間が長くなりすぎて、将来的に頭打ちになる 処理方式の転換 ➜ 複数バッチサーバ処理へと変更し、処理ペースを掛け算で確保できるようにする
    49. 49. ②マルチプロセス化 新しい処理方式 ①処理内容の細分化 ➜ 現在の処理を分割可能な単位で細分化する
    50. 50. ②マルチプロセス化 新しい処理方式 ②細部化された処理を実装 ➜ より細かい単位で処理を行う実装へと変更し、複数のサーバ実行に対応する 単位で処理を行う実装
    51. 51. ②マルチプロセス化 新しい処理方式 ③細部化された情報をキューイング ➜ 複数サーバが分割された処理対象を順次要求し、処理を行う キューについてはAWSのSQS(Simple Queue Service)を採用
    52. 52. SQSとは? Amazon Web Serviceが提供するキューイングシステム 安価で大量のメッセージの送信/配信をサポートし、SDKも公式で提供している ②マルチプロセス化 新しい処理方式 注意点 ・メッセージ配信時に同じものが取れる場合がある ・FIFOを保証していない
    53. 53. ②マルチプロセス化 処理サーバ1 処理サーバ2 新しい処理方式
    54. 54. ②マルチプロセス化 SQSの特性「メッセージ配信時に同じものが取れる場合がある」への対応 同一メッセージが何回も取れる場合、同じ処理を複数実行する可能性がある。 防止策としてRDS(MySQL)にて処理済みメッセージの管理テーブルを用意し メッセージ受信時に処理済みか否かのチェックを行うことで回避 (INSERT時の一意制約を活用)
    55. 55. 4章 「さいごに」
    56. 56. 結果 ここまでの施策によって・・
    57. 57. 結果 処理サーバ2台構成により実行速度が300%UP

    ×