はじめに
こんにちは。検索基盤部 検索基盤チームの佐藤(@satto_sann)です。検索基盤チームでは、 ZOZOTOWNの検索周りのシステム開発に日々取り組んでいます。
本記事では、ZOZOTOWNの検索マイクロサービスにおけるキャッシュ導入で得られた知見や工夫点について紹介します。検索に限らずマイクロサービスへキャッシュの導入を検討されている方の参考になれば幸いです。
キャッシュの導入背景
なぜ検索マイクロサービスにキャッシュを導入する必要があったのかについて紹介します。
負荷とレイテンシの悪化
現在ZOZOTOWNの検索システムは、既存の肥大化したシステムから検索に関連したAPI(以下、検索APIと呼ぶ)を切り離し、検索機能に特化したマイクロサービスで構成されています。
マイクロサービス化への道のりについては、以下の記事をご参照ください。
検索APIのマイクロサービス化に伴い、ZOZOTOWN以外のマイクロサービスから直接呼び出される機会が増加していました。
ZOZOTOWNからリクエストされる場合には、ZOZOTOWNを配信しているWebサーバ上にキャッシュする機構が以前からあったため、特に性能的な問題はありませんでした。
一方で他のサービスから直接呼び出された場合、検索APIはキャッシュ処理を行うような機構(以下、キャッシュ機構と呼ぶ)を持っていないため、負荷やレイテンシの悪化が課題となっていました。
ABテストの仕組みをマイクロサービスへ移設する上での問題
ZOZOTOWNではより良い検索機能を提供するためにABテストを実施しています。以下では、ABテストが振り分けられる様子を表しています。
これまでのABテストの仕組みでは、ZOZOTOWN上でABテストを設定していたため、以下のようなロジックの修正や設定の変更が必要でした。
- ZOZOTOWNのABテストの設定
- 既存キャッシュ処理のロジック
- 検索マイクロサービスのパラメータ
- 検索マイクロサービスの内部ロジック
ABテスト毎にこれらの変更作業が発生するため、短期的にABテストを実施する上で課題となっていました。
そこで、以下の図のように検索マイクロサービス上でABテストを実施する仕組み(以下、ABテスト基盤と呼ぶ)を構築して、ABテストの設定をこの基盤上で行えるよう変更します。
マイクロサービスに完結したABテストの実施が可能になり、設定や改修は以前と比べ少なくなります。
- ABテスト基盤の設定
- 検索マイクロサービスの内部ロジック
検索APIを直接利用していたネイティブアプリについては、これまでABテストを実施出来ていませんでしたが、ABテスト基盤が出来たことでWebと合わせてABテストが実施可能になります。
この仕組を実現するためにも検索APIにキャッシュ機構を導入する必要がありました。
キャッシュ導入の検証
検索APIにキャッシュ機構を導入すると前述した複数の課題が解決できますが、下記のような懸念事項がありました。
- Cache Stampede(キャッシュスタンピード)
- 2重キャッシュ
- キャッシュの有効期限
- 定められたタイミングでの情報反映
以下では、これらの懸念事項とその対策について詳しく説明します。
Cache Stampede
キャッシュが有効期限切れなどで破棄された際に、データ提供元(以下、オリジンと呼ぶ)へのアクセスが瞬間的に集中することで、APIやデータベースの負荷が高まります。 このような現象をCache Stampede(キャッシュスタンピード)と呼びます。
アクセスが少ない場合は特に問題になりません。しかし、検索APIが提供する検索機能はZOZOTOWNの多くのユーザが利用するため、キャッシュが破棄されたタイミングでCache Stampedeの発生が予想されました。
Cache Stampedeの対策
Cache Stampedeの対策はいくつかあります。
- 別プロセスで事前にキャッシュを生成する(事前作成)
- 期限切れ前に一定の確率で期限を更新する(期限更新)
- 裏側のAPIへアクセスするプロセスを絞る(ロック)
今回は、ロック方式を採用しました。任意のタイミングで更新情報を商品結果に反映する検索要件を実現しやすいことと、他マイクロサービスにて安定して運用している実績があったためです。
ロック方式の利点やその他Cache Stampede対策については以下の記事をご参照ください。
2重キャッシュ
背景で述べたとおり、現状リクエスト元のWebサーバ上で検索APIのレスポンスがキャッシュされています。検索APIにキャッシュ機構を導入すると、既存のキャッシュ処理を廃止するまで両方でキャッシュ処理される2重キャッシュ状態となり、キャッシュ効率の観点で懸念がありました。
しかし、どちらも一度キャッシュしてしまえば次の更新まで高速にレスポンスを返却できるため、この問題は許容出来ると判断しました。実際にリリース後の計測では2重キャッシュ状態でレイテンシは10ミリ秒増加しましたが、運用上は許容範囲内でした。
リリース後、リクエスト元で行われるキャッシュ処理をエンドポイント単位で無効化していき、段階的に2重キャッシュ状態を解消しました。これによりパフォーマンスとしてはレイテンシが数十ミリ秒減少し、大きな効果が見られました。
続きはこちら