成長し続けるサービスのAurora負荷への取り組み
はじめに
こんにちは。2024年4月より新卒で入社した齋藤です。システム基盤チームでインフラを担当しており、普段はロボアドバイザー(以下ロボアド)やデータベース周りの改善に取り組んでいます。
今回は、SRE meetup 〜サービス事業会社のSREが向き合う課題〜で登壇した内容についてご紹介します。
現状の課題
ロボアドでは、データベースにAmazon Aurora MySQLを利用しており、アプリケーションは90個以上、バッチに至っては1日に300個以上稼働しています。そして、それらは全て1つのAuroraに向いています。
そのため、プロダクトの成長とともにデータベース周りで以下の課題が出始めていました。
- アクセスが集中する時間帯とバッチが重なると性能劣化が顕著になる
- ユーザー数の増加に伴うレスポンス性能の低下
- ホーム画面の表示でレイテンシが悪化している
特に、スマホアプリのホーム画面でのAuroraからのレイテンシがかなり悪化していました。
そこで、現行アーキテクチャから別のアーキテクチャへの刷新を進めていました。アーキテクチャ刷新に向けた取り組みの詳細はJJUG CCC 2023 Fallの「持続可能なデータアーキテクチャを実現したリアーキテクティング」をご参照ください。
取り巻く状況の変化
アーキテクチャ刷新を進めていく中で、新たな問題が発生し始めました。
- 金融市場の相場が不安定になったことでアクティブユーザーが増加
- それに伴い、特定のバッチとアクティブユーザーが増加する時間帯で新たにスパイクが発生し始める
- バッチの実行スケジュールの調整も難しくなってきた
アクティブユーザーの増加によってデータベースへの負荷が短期間で急激に高くなったことで、早急に解決する必要がありました。
新しいアーキテクチャの採用
そこで、元々存在するスマホアプリ向けAPIとは別に、Readerインスタンス向けの参照用APIを新たに用意して、特定のエンドポイントからのリクエストのみをReaderインスタンスに振り分ける方式を採用しました。
メリット
- ホットスタンバイさせていたReaderインスタンスを活用できる
- インフラ側ですぐに対応可能
- スマホアプリ向けAPIの改修を必要としない
- 特定のエンドポイントからのリクエストを参照用のAPIに振り分けるだけでよい
デメリット
- Readerへ振り分ける読み取り負荷の調整が必要になる
- Reader参照用のECSサービスが増えることによるコストの増加
採用理由
ロードバランサーを利用したReader振り分け方式を採用した理由は、スマホアプリ向けAPIの改修が不要であり、インフラ側で対応可能というメリットがあったためです。Auroraへの負荷の高い時間帯では、スマホアプリからのリクエストが全体の約半数を占めており、負荷の高いSQLクエリのほとんどがスマホアプリ向けAPIから実行されていることがわかりました。
そこで、バックエンド開発者およびAssociate CTOと協議し、Associate CTOからの提案で、特に負荷の高いSQLクエリが実行されるエンドポイントのみをReaderへ振り分けることになりました。短期間で急激にAuroraへの負荷が高まったため、スマホアプリ向けAPIの改修を待つよりもロードバランサーで振り分けたほうが最短でAuroraへの負荷を軽減させることができると判断しました。
検証方法
ロードバランサーでのReader振り分けをリリースするにあたって、以下のテストを実施しました。
- アーキテクチャ検証
- 負荷テスト
- 障害テスト
- リグレッションテスト
その中でも、特に苦労した負荷テストについてご紹介したいと思います。
負荷テストツールにk6を利用しており、実際のユーザーの行動パターンを基になるべく本番環境に近い負荷がかかるようなシナリオになるように実施しました。k6の詳細については「k6で始めるパフォーマンステスト」に詳しく書かれていますので、 そちらをご参照ください。
負荷テストを行う中で出た想定外の課題
つい先月、今後のマルチプロダクト化に向けて1つの共通IDで各サービスを利用できるようにするための共通ID基盤をリリースしました。具体的には、認証認可基盤をOkta CIC(Auth0)に移行することで、各プロダクトの認証認可プロセスとユーザーIDを共通化するものとなります。しかし、それに伴って認証認可プロセスが大きく変わったことで、負荷テストの実施がかなり難しくなりました。
Auth0には、様々なセキュリティ機能が用意されています。負荷テストを実施するにあたって大量のユーザーをログイン認証する必要があるのですが、一度に大量のユーザーのログイン認証をk6スクリプトで実行しようとすると不正ログインや不正アクセスを検知する仕組みに引っかかってしまうという問題がありました。
そこで、Auth0で設定されている不正検知機能を無効化して、リクエストレートリミットに引っかからないようにログインリクエストを調整しました。その際に、Auth0とアプリAPI側のアクセストークンの有効期限を本番環境で設定されている期限よりも伸ばすように設定を変えることで、負荷テストのような大量のユーザーを利用してテストしなければならないケースにも対応できるようにしました。
負荷テスト結果
Reader振り分けを実施した結果、Writerへの負荷の半分をReaderに分散させることができ、総合的な負荷で計算すると、2/3までに軽減させることができました。
- Writer: 90.62 → 36.35
- Reader: 0 → 32.03
また、レスポンスタイムについても、大幅に改善されることがわかります。
- avg : 1.4s → 1.01s
- p(90): 4.13s → 2.76s
- p(99): 5.11s → 3.46s
Next Action
今回は、Readerへの負荷分散の取り組みを紹介しましたが、まだ他にも課題が残されています。
- Readerの積極的な活用
- 新たなアーキテクチャへの刷新
- データベース周りの運用改善プロセスの整備
まずは、新たなアーキテクチャへの刷新を進めつつ、さらにReaderを積極的に活用していく予定です。一方で、一時的にAuroraへの負荷分散はできるものの、負荷は依然として高い状態が続いています。
最終的には、今のデータベース周りの運用を開発者を巻き込んで改善することが重要です。今後の課題として、データベース周りのモニタリングの強化や改善できる仕組みを構築していきたいと考えています。
Discussion