Webサービスでは、Solr、Elasticsearchをはじめとする検索エンジンの結果をキャッシュしたいことは比較的よくあるはなしではないだろうか。ユーザー向けに提供している検索では、人気のワードで検索されやすく、それ相応の負荷になる。また、コンテンツに付加されているタグをクリックすると同じタグが付けられているコンテンツが検索される事例など、おなじようなクエリが投げられやすい状況は容易に推測できる。
さて、このような場合検索エンジンにおいてはどのようなキャッシュ戦略をとれば良いか。
1. Solr、Elasticsearchなどの検索エンジンに内蔵されているキャッシュ機能を利用する
ElasticsearchではFilterCache、SolrではさらにFilterCache、QueryResultCache、documentCacheなどより細かなキャッシュ機能を利用できる。これらのキャッシュはすべてメモリキャッシュであり、それほど大きなキャッシュ容量は期待出来ないが、最低限のキャッシュとしては有効だ。また、検索エンジン自体に内包されているキャッシュであるため、インデックス更新などで適切に破棄される。
-
メリット:
- 検索エンジンの設定だけで提供することができる
- キャッシュのウォームアップができる
- インデックス更新で適切に破棄される
-
デメリット:
- インメモリキャッシュであり、大きなキャッシュ容量は期待できない
- 検索エンジンとリソースを共有するのでチューニングが難しい
- コンテンツの内容や属性によってキャッシュを制御するのは難しい
2. アプリケーション側でキャッシュする
次に思いつくのがアプリケーション側で取得した検索結果をキャッシュする方法である。アプリケーション側でRDB、KVS等のデータストアを用意し、検索結果をキャッシュする。ミドルウェアとしてはMemcached、Redisなどが一般的だろうか。
この方法では、アプリケーション側に実装があるので、アプリケーションの機能やコンテンツの内容、属性によってキャッシュするかどうか、更新頻度、有効期限を調整しやすい。アプリケーションの性質に合わせたきめ細かな設定ができるのが特徴だ。
反面、キャッシュ機能がアプリケーションと密結合してしまうため、APIとキャッシュの両方の面倒を見なければならず、コードの可読性は低下し、メンテナンスしづらくなる。また、1つのミドルウェアのAPIを複数のアプリケーションから参照している場合、それぞれのアプリケーションでキャッシュ機能を実装する必要も出てくる。
-
メリット:
- アプリケーション固有のキャッシュ機能を提供できる。
- アプリケーションの変更だけで設定変更が出来る。
- コンテンツの内容、性質に応じて更新頻度、有効期限を設定できる。
-
デメリット:
- アプリケーション上でキャッシュの管理を行わなければならない
- 複数アプリケーションでキャッシュの共有ができない
- API側の負荷に応じたキャッシュ調整が難しい
3. APIをプロキシ経由にすることでキャッシュする
3番目の方法は、アプリケーションとAPIをもつミドルウェアの間にプロキシを設置しキャッシュを行う方法である。キャッシュ機能を持つプロキシとしては、nginx、Varnish Cache、Apache Traffic Server、Squidなどが挙げられる。これらは特にミドルウェアに特有のキャッシュ機能を提供するわけではなく、標準的なHTTPレスポンスの殆どをキャッシュすることが出来る。
この方法では、アプリケーションに変更を加えることなく、キャッシュ機能を提供できる。また、インメモリではなくディスクを利用したキャッシュも可能であり、大容量のキャッシュを実現できる。アプリケーションに手を加えないため、API側の負荷に応じて適切なキャッシュの有効期限を設定することが可能だ。弊社では、この方法でSolrの検索結果をキャッシュしている。
-
メリット:
- アプリケーションコードの変更が必要ない
- キャッシュだけの設定をすれば良いので、設定が比較的簡単
- 大容量のキャッシュを実現できる
-
デメリット:
- アプリケーションに固有のキャッシュ調整の実現は難しい
- HTTP APIによる応答しかキャッシュすることが出来ない
- 運用するプロダクトが1つ増える
まとめ: 銀の弾丸はない
まあ、だいたいの場合そんなものはない。どの方法も一長一短あるし、組み合わせて使うこともできる。アプリケーション特有のキャッシュであればアプリケーションでカバーすればよいし、そうでなければプロキシキャッシュも候補に入るだろう。Kusabanaのようにアプリケーション特有のキャッシュ機能をもったプロキシもあることはある。また、そもそもSolrやElasticsearchではリソースにあわせて必要十分なキャッシュ設定を行うべきであろう。
注意しなくてはいけないのは、実際のWebアプリケーションではこの3つをうまく組み合わせて作る技術が必要になる。しかし、透過的ではないキャッシュ機構はシステムの複雑性を確実に増加させる。それぞれの場合に応じて、適切な判断が必要だ。
アプリケーションの速度と開発速度のトレードオフを見極め、ユーザーに適切に価値を提供できるシステムを目指さなくてはならない。もしくはハードウェアの進歩を夢見るかである。