Case Study for Implementing Caching

写真ページ GANCHIKU.com
写真ページ GANCHIKU.com

Symfony2 のアプリケーションで API のレスポンスをキャッシュ をしたいときに便利なバンドル LiipDoctrineCache を使ってみました。実際にこのサイトの写真のところにも使われています。

Symfony2 のドキュメントに載っているキャッシュは HTTP Cache のことでここで扱うキャッシュとは別ものになります。今回の投稿では、サーバ側が生成する一時ファイル等をキャッシュするケース・スタディとして API のレスポンスをキャッシュ化したときの内容を説明します。

GANCHIKU.com の写真について

このサイトの写真のところの説明を少しします。今回ブログの仕組みを作成するにあたって、サーバ上に写真をアップロードするところを実装するのが面倒であったため、写真のアップロードは全て Flickr に任せてあります。全部大した写真ではないのですが、私が昔旅行にいったときにとった写真です。ずっとローカルのパソコン内に眠っていたのですが、一発奮起してネットで保存しておこうと思い、Flickr の有料アカウントを最近取り、全部そこに挙げてみました。

しかし、せっかく自分の写真だし、 Flickr 上でしか見れないのは寂しいじゃないですか。ぜひ自分のサイトに組み込もうと思いました。こういうときに API って便利ですね。全部自分が撮った写真なので、著作権は私のものになりますので、勇気を持って自分のサイトに貼り付けることができます。

Flickr API

Flickr API
Flickr API

さて、 Flickr の API は公開されていて、たくさんの API がありますね。私が今回使用したのは、 次の3つです。

  • flickr.tags.getListUser
  • flickr.photos.search
  • flickr.photos.getSizes

flickr.tags.getListUser

getListUser で、私が登録した全てのタグを持ってきます。それをサイドバーなどに入れておいて、タグを選べるようにしました。

flickr.photos.search

そして、その選んだタグで searchに問い合わせし、写真を検索します。また、searchでは、tag_mode で AND と OR を切り替えるようにしています。その他、page を使うことによりページングも対応した検索をするようにしています。

flickr.photos.getSizes

それぞれの写真にはあまり情報は入れていないのですが、flickr でアップロードするといろんなサイズを生成してくれます。つまり、ウェブで使うのに適したサイズや、オリジナルのサイズなどです。これをsearch で得られた photo_id で検索して、個々の写真のサイズ情報を取得するようにしました。

さて、残念ながら私は最近は旅行をしなくなっているので、写真の更新は基本ありません。それなのに毎回 Flickr の API を叩いていたら、サイトの読み込みが遅くなってしまいますね。もちろん、JSONP などで、全部クライアントサイドでやってしまうというのも1つの手なのですが、今回は JavaScript での実装は触れません。PHP 側のキャッシュのみを扱います。ようやくここでキャッシュの必要性が出てきました。

No more KnpZendCacheBund

このサイト自体は、3つのAPI のレスポンスをキャッシュ化します。さて、ちょうど一年前 Symfony2.0 の頃に少し API を使用した勉強サイトをいくつか作ってみました。その際にもキャッシュを使用していた。その際に使用していたバンドルは、 KnpZendCacheBundle です。すごく使い勝手は良かったのですが、Zend_Cache を使うところ等の関係でインストールが面倒になってしまいまいした。現在では、 KnpZendCacheBundle は KNP の名前が付いているものの、もうメンテナンスがされていません。

Move to LiipDoctrineCacheBundle

で、代わりに何を使ったらいいのだろうか、と調べていたときに見つけたのが、LiipDoctrineCacheBundle です。 Doctrine/Common にはいろんなキャッシュ戦略を実装されています。PHPファイルだったり、APC だったり、memcached だったり。Doctrine という名前が付いているものの、データベースとは関係なく使用することができます。 直接そこでDoctrine/Common のキャシュを使用してもいいのですが、これをうまく被せているバンドルが LiipDoctrineCacheBundle です。Symfony のサードパーティのバンドルでは、 FOS, Knp, JMS, Liip 辺りはメンテナンスされている状態であれば、採用してもいいと考えています。じゃあ、上のKnpZendCacheBundle はどうなんだ!と突っ込まれそうですが、 もうメンテナンスを放棄しているので、できるだけ使わない方がいいですね。ちょっとややこしい。。。

具体的なコード

詳しい設定に関しては、ドキュメントを参照したらいいのですが、とりあえず動かす構成としては、私は次のように書いてみました。

キャッシュ戦略に file_system を使用しました。 namespace を切り替えて APC を使いたいとかうまく切り分けることもできますが、今回は、全部 Flickr API のレスポンスをするだけなので、一番シンプルだろうと思われる file_system になっています。

コントローラーからは、config.yml に書いた設定を呼び出し、キャッシュキーを見て、有効期限にキャッシュがないときに実際に API にアクセスしにいき、そうでないときは、全部キャッシュを使うようにしています。

で、実際に格納されるキャッシュの保存先ですが、 /app/cache/(prod|dev)/cache/ 以下になります。これで、 API のレスポンスをキャッシュ化することができました。 config.yml に少し書いて、コントローラーから呼び出すだけです。すごく簡単で便利ですね。 Symfony2.1 の間は LiipDoctrineCacheBundle を使用するといいと思います。

Symfony2 を使いはじめて思うことは、書くコードの量が減ったなぁ、ということです。いろんなバンドルが用意され、また、拡張性も高いため、あまり自分が書くことなくすっきり実装することができるようになったと思います。

comments powered by Disqus