【デジカルチーム ブログリレー4日目】
こんにちは。デジカルチームでエンジニアをしている武井です。
デジカルチームでは、クラウド型電子カルテ、エムスリーデジカルを開発しています。
今回は、非同期処理基盤のリアーキテクチャを実施し、性能も向上しつつインフラコストを60%以上削減できた話をご紹介します。
非同期処理基盤の課題
エムスリーデジカルではサービス開始当初から多くの機能で非同期処理の仕組みを活用してきました。ここでの非同期処理とは、ユーザーからのリクエストに対して処理を即座に実行せず、一度キューにジョブを積んでからバックグラウンドで処理を進め、完了後に結果を通知する形式の処理のことです。これにより、帳票出力など時間のかかる処理を実行してもユーザーの操作をブロックせずに済み、利便性と安定性の高いサービスの提供を可能としてきました。
この非同期処理を実行する基盤には、サービスの成長とともに様々なジョブが追加され続け、現在では40種類以上のジョブが定義されるまでに拡大しました。動作環境としてはRuby on Railsと相性の良いDelayed::Jobを利用しており、RDBの1つのテーブルをキューとして使用し、ECS on EC2で起動している複数台のワーカーで処理を行っていました。
40種類以上あるジョブの中には、大量のデータを扱うために数時間かかるようなものもあります。こういった重いジョブがいつキューに入ってきても対応できるよう、高スペックなEC2インスタンスを複数台、24時間起動していたため、AWSの料金がかさんでいました。
また、当時は大きな問題なくジョブを捌くことはできていましたが、月初や連休明けなど負荷が増加傾向にある期間を予測することで、より性能を高められる余地もありました。
これらの課題解決および性能向上を実現するため、非同期処理基盤のリアーキテクチャを実施することにしました。
ジョブの特性の分析・分類
リアーキテクチャの第一歩として、既存の全てのジョブの特性を詳細に分析しました。メトリクスをもとに各ジョブの実行頻度と平均的な実行時間を調査した結果、次の3つのカテゴリに分類できることがわかりました。
カテゴリ | 例 | 実行頻度 | 実行時間 |
---|---|---|---|
集計ツール系のジョブ | 月ごとのレポート出力 | 月に1回など少ない | 数時間かかるものもあり長い |
内部向けツール系のジョブ | サービス導入前のデータ準備 | 1日に数回程度と少ない | 数時間かかるものもあり長い |
日常業務に関わるジョブ | 検査結果ファイルの取り込み | 1時間に数回程度と多い | 基本は数分程度と短めだが、データ量によっては15分を超えることがまれにある |
この詳細な分析結果を踏まえ、すべてのジョブを従来の画一的なシステムで処理するのではなく、それぞれのジョブの特性に最適化されたシステムで処理することにしました。
リアーキテクチャの全体像
分析結果をもとに、次の2ステップでリアーキテクチャを進めました。
ステップ1: 一部ジョブのコールドスタンバイ方式への移行
実行頻度が少なく処理時間の長い「集計ツール系のジョブ」と「内部向けツール系のジョブ」については、従来のリクエストがキューに入ってくるのを待ち構えるpull型のホットスタンバイ方式ではなく、push型のコールドスタンバイ方式が適していると判断しました。具体的には、ユーザーから処理開始のリクエストを受けてから、AWS Step Functions経由でECSのRunTaskを使用して、都度Fargateを立ち上げて処理させる方式です。
この方式では、Fargateを立ち上げるための時間*1が追加でかかってしまいます。一方で、ECS Taskの常時起動は必要なくなり、ジョブが動いている間の分だけのコストで済むため、従来の方式よりも高スペックなインフラリソースの利用が可能になります。結果的にそもそも処理自体に長い時間がかかっていたジョブであれば、全体としてみると処理の高速化が図れると考え移行を進めました。
ステップ2: ホットスタンバイ方式のリソース最適化
一方、実行頻度が多く、処理の即時性が求められる「日常業務に関わるジョブ」は、引き続きホットスタンバイ方式での運用を維持することにしました。ただし、ステップ1で数時間以上かかる極端に重いジョブが切り出されたことで、インスタンスタイプと台数の見直しが実施でき、大幅なコスト最適化につながりました。さらに、10年前の実装当時にはなかったECSのCluster Auto Scaling*2を導入し、ECS on EC2の環境でも負荷に応じてワーカーが自動で増減するように設定しました。
この改善により、負荷が増える期間を予測して事前にワーカーを増強したり、突発的なジョブの急増時にも自動で対応したりすることが可能となりました。これにより、コストの最適化と可用性の向上を両立させ、より柔軟で堅牢な非同期処理基盤を実現しています。
なお、AWS Lambdaの利用も検討しましたが、15分の実行時間制限*3がネックとなりました。外れ値ではあるものの過去の実績として処理に15分以上かかる場合があったことや、将来的なデータ量の増加に伴う処理時間の長期化を考慮して今回は採用を見送りました。
移行作業で意識したこと
実際の移行作業にあたっては、次の2点を意識して進めていきました。
タスクフォースによる計画的な移行
リアーキテクチャ専門のタスクフォースを結成し、「1人あたり月にnジョブ」といった目標を決め、計画的に移行を進めました。結果として、各メンバーが他の機能開発などのプロジェクトを進めつつ、並行して今回のリアーキテクチャのような中長期的な技術的観点の改善を推進できました。
カナリアリリースによる安全な移行
インスタンスタイプの変更やオートスケーリングの導入など、大きな影響があるリリースについては、カナリアリリースを実施しました。具体的には、全トラフィックの一部を新しい基盤に流し、問題がないことを確認してから変更を適用する割合を増やしていきました。
このアプローチにより、サービスのクリティカルな部分で多く使われている非同期処理基盤を無停止で安全に移行できました。
成果とまとめ
約半年にわたるリアーキテクチャの結果、次のような成果に繋がりました。
インフラコストの削減
高スペックなEC2インスタンスを24時間常時起動していた従来のシステムから、需要に応じて柔軟にスケールするシステムに変更したことで該当システムのインフラコストを60%以上削減できました。こういった定量的で分かりやすい指標の変化はチーム全体のコスト意識の向上にも繋がっていると感じています。
可用性の向上
需要に応じて自動的にリソースを増強できるようになったことで、短期的な負荷の増減や、中長期的なデータ量の増大に耐えられるようになり可用性が向上しました。また、コールドスタンバイ方式に移行した一部のジョブについても、移行前と比較して実行時間に大きな差はみられず、期待通り安定して稼働しています。
運用負荷の軽減
以前は、複数の重いジョブが実行されるとワーカーが占有され、まれにキューが詰まってアラートが鳴ることがありました。サービスの提供が止まるほどの影響はありませんでしたが、開発メンバーにとって運用上の負担の一部となっていました。今回の移行後はこういったアラートがほぼ無くなり運用負荷が軽減されたと感じています。
今後も、エムスリーデジカルでは、サービスの安定性を維持しながら、新しい技術を積極的に取り入れ、より良いサービスを提供していきます。
We are hiring!!
デジカルチームでは、このような技術的な挑戦に一緒に取り組んでくれるエンジニアを募集しています!少しでも興味をもってくださった方はぜひご連絡ください!
*1:我々が検証した環境では平均で1分半ほどでした。環境によって変化する可能性もあるので、ご自身で検証した上でご判断ください。
*2:https://docs.aws.amazon.com/ja_jp/AmazonECS/latest/developerguide/cluster-auto-scaling.html
*3:記事を書いている時点での値です。最新の情報は公式サイトをご確認ください。