モノリシックなECSサービスを分離して安定稼働とコストダウンを実現した話
概要
私達が開発・運用しているサービス「Cariot」ではAmazon ECS Service上で稼働する、通称「web」と呼ぶアプリケーションがあります。これはフロントエンド向けAPIと定期バッチ実行APIの2種類のAPIを同居したモノリシックな構成になっていました。
最近このアプリケーションがしばしば不安定になり、ユーザーに影響する障害が発生することがありました。
対応として2種類のAPIを個別のサービスに分離したことで問題が解消し、副次的にリソースコストを抑えられました。
背景:フロントエンドとバッチが同居する構成
もともと私たちのシステムでは、「web」と呼ばれる一つの ECS Service に、下記 2 種類のリクエストが集約されていました。
- フロントエンドからのリクエスト
- バッチのリクエスト
- イベント/定期起動するLambdaから、「web」のバッチ起動APIをリクエスト
- バッチは複数存在
この構成では下記2つの課題がありました。
- バッチのピーク時、API レスポンスが遅延し、ユーザー体験を損ねてしまう
- 原因切り分けが難しい
- 不調が起きた際、「フロントエンド側の問題か、バッチの側の問題か」すぐには分からず、調査に手間がかかる
- 同じサービスで両方のリクエストを処理しているため、メトリクスを見てもどちらが原因か判断がつきにくい
結果、障害発生時の取り急ぎのユーザー影響を解消するため、スケールアウト等で対応している状況でした。
対策:ECS ServiceをAPIごとに分割し、役割を明確化
対策はシンプルで、フロントエンド側APIを担当する「API」とバッチ実行担当する「batch」の個別のECS Serviceに分離しました。
分離後の効果
「web」の安定稼働とスケールイン
分離後、「web」のメトリクス(CPU・メモリ利用率)を確認すると、これまで散見されていたスパイクが大きく抑えられ、安定稼働するようになりました。
結果として、課題であった動作の不安定さはバッチに起因するものであると推測できるようになりました。
また、副次的に、現行のスペックが不要なことがわかり、スケールインできました。
今後スケールダウンも検討しており、「batch」を追加した分を含めてもトータルでコストダウンも可能になりました。
矢印の箇所で、バッチの分離を順次実施:
「batch」の稼働状況
一方、新たに切り出した「batch」は、バッチ実行時に CPU/メモリ利用率がスパイクするものの、こちらも安定稼働しています。
また、「web」と分離したことで、今後の原因切り分けも容易になりました。
スパイク時はCPU使用率が100%になっているため、これは解消すべき課題と考えています。
恐らく、スケジュール実行したバッチがそのまま負荷になっているため、時間的に分割し平準化できないか検討しています。
まとめ
- ECS Service の分割により、バッチ負荷がフロントエンドへ波及する問題を解消
- メトリクスの安定化とスケールインにより、コスト削減とユーザーへの影響低減を同時に実現
今後もモニタリング継続的し、必要に応じてスケーリングや設計の見直しを進めていく予定です。
所感
本取り組みは当初、障害時の切り分けを容易にすることだけを目的にしていたのですが、結果としてコスト削減にもつなげることができて良かったです。
また、実施前の仮説としてモノリシック構成時の負荷の原因はフロントエンドのAPIだと考えていたのですが、実際は「web」単体だと安定しており、改めて試すことの大切さを感じました。
最後に、分離後の構成について、今見ると自然な設計という印象を持っているのですが、歴史的にはインスタンス数を抑えながら最小限の実装で機能を実現しようとした経緯もあります。一般論ですが、やはり継続的に改善を試していくことが重要だと感じています。
Discussion