積極的キャッシュ生成による応答高速化
LAPRAS株式会社でソフトウェアエンジニアとして勤務していることねです。本年の上期、弊社で開発・運営を行っているITエンジニア向けサービス「LAPRAS」のパフォーマンス・チューニングに取り組みました。そこで実施した内容についてニッチながら似た状況にあるサービスに応用できるのではないかと思い記事をしたためました。
背景
通信技術の発達に伴いWebページの表示は1ミリ秒がユーザ体験を左右する時代に突入しています。そんな時勢にあって弊社のエンジニアポートフォリオサービス「LAPRAS」は長らく社内でも「遅い」という声が上がる程に応答時間が長いという課題を抱えていました。しかもLAPRASとして一番応援している「アウトプットが多いユーザ」ほどポートフォリオLCPまでの待機時間が長くなる傾向があったため問題視こそされていたものの、これといった対応策が打てないまま時間だけが過ぎていきました。
Datadogに蓄積されたTraceデータからわかっていたボトルネックは大きく2つありました。一つはアウトプット情報の一次データを保管しているDynamoDBからのデータ取得が応答時間の大部分を占めていることで、もう一つはLAPRASからアウトプット情報を取得するためにアクセスしているgRPCサーバーのワーカーに異常な負荷がかかっていること。以前SLA違反の対策を講じた際に、1+Nに起因して長時間に亘ってサーバのリソースを占有していた特定のgRPCサービスを修正したことでgRPCサーバ全体のパフォーマンスが改善した事例から、リソース占有率の高いサービスメソッド≒DynamoDBへの問い合わせに最も時間のかかっているサービスメソッドをチューニングすれば全体の改善がみられるであろうという期待がありました。
課題
データの問い合わせを高速化する手段として真っ先に検討されるのが「キャッシュの導入」ですが、LAPRASについてはすでに簡易的なキャッシュの仕組みがありました。具体的にはDynamoDBから取得した情報をRedisに登録し次回問い合わせがあった際にそのデータを参照するというものです。ただこのアプローチには問題がありました。
一つ目はLAPRASからの問い合わせ以外の用途にも使用される可能性があるためLAPRASから必要な情報に限定することなくDynamoDBから取得したデータを全て保存していたためストレージ効率が悪かったことです。このためキャンペーン等でアクセスが集中した際に頻繁にキャッシュ破棄が発生しキャッシュミスを誘発するという状況を招いてしまっていました。
二つ目はユーザのアクセス頻度と情報の更新頻度の噛み合わせがイマイチでキャッシュのヒット率が悪かったことです。アウトプットが更新される頻度は比較的多いユーザでもならして数日単位で、LAPRASへのアクセスも数日単位です。そもそもポートフォリオをメインに使われているユーザの方であればアウトプットの更新タイミングでスコアを確認するといった用途でログインされる方が多いというのが実情です。ログインしたタイミングではほぼ確実キャッシュは古くなっていますし、そうでなくても有効期限切れで失効しています。一度ログインすればその日のうちは応答が改善しても後日またログインしたら遅かった、なんて経験がおありの方もいらっしゃると思います。
解決方法
この両方の問題を解決するべく考案・実装したのが「積極的キャッシュ生成」でした。ユーザがアウトプット情報にアクセスした時に初めてキャッシュを生成していた従来の方法とは逆に、アウトプット情報が更新されたことを検知したタイミングで積極的にキャッシュを生成しておくというキャッシュ生成戦略です。これはキャッシュ生成に必要なタイムラグに対してユーザのアクセス間隔とデータの更新間隔が十分に長い場合に有効な方法です。生成されるキャッシュのデータ量はユーザー数のオーダーを10^5~10^6程度、一人当たりのデータ量を実測値から10^4バイト程度と見積もった場合に10^9~10^10バイト、おおよそ数GBから数十GBのオーダーに納まるためgRPCサーバに直結しているRDBに置いても当座は問題のないスケール感と判断しました。
効果
以下にチューニングした各エンドポイントについて、リクエスト応答時間の分布をプロットしたものです。
いずれも分布の形は大きく変化していませんが、横軸が大きく変化していることがわかると思います。
ユーザアクティビティ情報
before
after
ブログ記事情報
before
after
GitHubリポジトリ情報
before
after
結論
今回実装したキャッシュ戦略で十分に効果を得るためにはデータの更新頻度がキャッシュ作成にかかる時間に対して十分に長くかつリアルタイム性がクリティカルでない必要があります。そういったケースに該当する場合は有力なパフォーマンス改善メソッドになると思いますのでご参考になれば幸いです。またここでご紹介した事例はgRPCサーバー上でのレスポンスに対してキャッシュを作成しましたが更にアグレッシブに最終的にレンダリングされるページ(SPA)自体を事前に生成しておくといったこともサービスによっては可能だと思います。
Discussion