ReviCoのパフォーマンスチューニング奮闘記 その2

こんにちは。ecbeing金澤です。

レビューのSaaSサービス「ReviCo(レビコ)」を開発しています。

はじめに

前回のパフォーマンスチューニング奮闘記から2年経ち、おかげさまでReviCoは導入170サイト突破、運営母体も(株)ReviCoとして親会社からスピンオフしました。

サービスの成長に伴いどんどん増えるトラフィック量やデータ量に圧倒されつつ、開発チームでは「ReviCo 365」というスローガンを打ち出し(もちろんMicrosoft 365のオマージュです)、365社に導入してもらえるサービス・365日安定稼働するシステムを目指して開発とチューニングを行っています。

今回の記事では、この2年間で実施したパフォーマンス改善施策についてまとめたいと思います。

パフォーマンス改善のためにやったこと

検索エンジン導入

効果:★★★
難度:★★★

レビュー表示のデータ取得に Amazon OpenSearch Service を導入しました。

検索エンジンの知見が無かったので、導入にかなり時間が掛かりました(調査開始からリリースまで3か月くらい、データ移行とバグ修正で+2か月くらい…)が、DBの負荷削減とレスポンスタイム短縮に劇的な効果を発揮しました。

まだ全検索クエリに対しての導入率は50%程度で、複雑な絞り込み条件の場合はDBに切り替えたりしているので、費用対効果が頭打ちになるまでは導入率を上げていきたいと考えています。

(OpenSearch上でテーブル結合ができず、表示に使用する全データを1レコードとして保持しないといけないので、ちょっとしたデータの修正で大量のレコードが更新対象になってしまうのが悩みです…)

API Gateway + Lambda のサーバーレスアーキテクチャー導入

効果:★★★
難度:★★★

新機能を作った際に、API群を既存のECSではなく、サーバーレスアーキテクチャーで動かすようにしました。

ざっくり構成図です。非常にオーソドックスなつくりだと思います

ECSはオートスケールの設定やスケーリングするタイミングにかなり気を使う必要がありましたが、こちらはその辺を気にする必要が無いので非常に気が楽です。サーバーレスってすごい…!

APIからDBを直接見に行けないことがたまに設計の制約になりますが、それを上回るメリットがあると思います。

POST系APIの非同期化

効果:★
難度:★★

上記のサーバーレスアーキテクチャーを参考に、既存のPOST系APIについても、可能なものは間にSQSを挟んでデータ更新処理を非同期化しました。

処理に時間が掛かるとWebサーバーのコネクションを持ったままになってしまい、更に処理の滞留を引き起こしてしまっていたのですが、それが解消できたことでECSのコンテナ数が安定するようになりました。

スロークエリのチューニング

効果:★★★
難度:★

上記のような大掛かりなアーキテクチャー変更はたまにしかできないので、結局日々の保守でスロークエリをこつこつ潰していくのが一番大事なのではないかなと思います。

ReviCoでは統合監視ツールとしてnew relicを導入していて、そこでスロークエリを拾ってチューニングしています。

new relic のダッシュボード。システムの指標だけでなく、レビュー投稿数や管理画面のログイン数などサービスの指標も可視化しています

スロークエリ自体はAuroraの機能でも出せるのですが、new relicでは呼び出し元のURLが分かるので、問題のクエリが書かれているコードまで早く到達できるのが便利です。(APMと組み合わせると更に深堀りできます)

また、秒数とコール回数をまとめてくれているので、改善効果の高いクエリを簡単に判断することができます。

チューニング自体は勘と経験と気合でやります。(笑)

LOAD DATA FROM S3 の活用

効果:★★★
難度:★★

レビューの一括インポート処理で、インポートデータをループで1行ずつDBにINSERTしていたのを、一旦CSVにしてS3に上げた後に LOAD DATA FROM S3 で一発ロードするようにしたところ、処理が10倍速くなりました。

(MySQLのバルクインサートも試しましたが、LOAD DATA FROM S3 の方が高速でした)

実装したメンバーが非常に喜んでいました。

SQS(FIFOキュー)の高スループットモードの活用

効果:★★
難度:★

初期の設計ではFIFOキューの必要があったものの、今はそうでもなくなったバッチがいくつかあるのですが、データ量の増加にともなって処理が滞留するようになってしまいました。

とはいえ標準キューへの移行は大変だなぁ…と思っていたら、高スループットモードをONにするだけで一気に解決できました。

(キューを積む際にMessageGroupIdがバラけるように修正する必要はあります。振り分けを気にする必要も無かったのでGUIDを都度生成するようにしました)

クリティカルなAPIとそうでないAPIのコンテナを分離

結果:見送り

アクセス集中などがあった際に、ECSのスケールが間に合わないとコンテナ全滅に繋がってしまうのですが、現状すべてのAPIが同じECSサービスにいるので、クリティカルなAPIは別サービスにすることで全滅を免れようと考えました。

最初からその思想でURLなどを設計していればさほど難しくなかったと思うのですが、途中から切り離そうとするとALBのルーティングが複雑になりすぎて、諦めました…。

今は既存APIを順次サーバーレスアーキテクチャーに乗せ換える方向で検討しています。

Aurora Serverless v2 の導入

結果:見送り

GAをとても心待ちにしていたのですが、結局全額前払い RI を買った方が安かったのと、検索エンジン導入などでDBの負荷がかなり下がったのと、何よりAuroraを3系にバージョンアップしなければいけなかったので、導入を見送りました…。

(Auroraを3系にすればRedShiftのゼロETL統合もできるし、インスタントDDLも使えるし良いことづくめなんですが、メジャーバージョンアップはハードルが高い…!)

まとめ
施策 効果 難度
検索エンジン導入 ★★★ ★★★
API Gateway + Lambda のサーバーレスアーキテクチャー導入 ★★★ ★★★
POST系APIの非同期化 ★★
スロークエリのチューニング ★★★
LOAD DATA FROM S3 の活用 ★★★ ★★
SQS(FIFOキュー)の高スループットモードの活用 ★★
クリティカルなAPIとそうでないAPIのコンテナを分離 見送り…
Aurora Serverless v2 の導入 見送り…

おわりに

パフォーマンスチューニングはインフラからのアプローチとアプリケーションからのアプローチがありますが、ReviCoの場合はインフラもアプリもすべて開発チームで面倒見ているので、色々な手段を検討・実施できるのが大変であり面白いところだなと感じています。

特にクラウド関連の技術は進化が激しく、便利な機能が次々と出てくるので、乗り遅れることなくその恩恵をたっぷり受けてサービスの成長に繋げていきたいと思います。

(まずはAuroraを3系にバージョンアップしなきゃ…)

お知らせ

ecbeingではサービスの成長のため一緒に試行錯誤してくれる仲間を募集しています! careers.ecbeing.tech