QA@IT

Apacheにキャッシュを持たせる際のいくつかの問題点

3498 PV

現在Rails3.2,Apache2.2をつかっているのですが、どのようにすればキャッシュをうまく使って負荷対策できるのか分からず質問させていただきました。

  • 背景、状況説明

具体的な状況を説明させていただきます。

最近サイトが重くなってきました。
そこでサイトのコンテンツの更新頻度も低い事も考慮して、負荷対策のためにApacheにキャッシュを置いて、リクエストがきたらそのキャッシュを返す事により、Railsに毎回アクセスしなくてもいいようにしようと考えました。
このキャッシュを保存する機能は、Apacheのモジュールである「mod_cache」を使いました。

Railsのレスポンスのキャッシュを保存する際に、気をつけた点があります。
それは私のサイトはUser-Agentによって、スマフォ用、PC用とレイアウトを使い分けているため、同じURLにPCとスマフォがアクセスした場合、お互いのキャッシュが混ざらない様にする点です。

そこで私はRailsのコントローラ内で

    expires_in 2.minutes, :public => true
    response["vary"] = "User-Agent"

と書く事によりVaryにUser-Agent指定しました。
これのおかげで「URL*ユーザエージェント毎」のキャッシュを保存することにより、スマフォ用とPC用のレイアウトがまざらないようになる予定でした。

しかしながらここでいくつか問題が発生しました。

  • 問題点と質問

1、User-Agentは無数にあるためUser-Agent毎にキャッシュをさせていてはきりがありませんでした。そこでUser-Agentに対してこれはMobileかPCかという判断をApacheにやらしたいのです。しかし、この方法に関する問題点も2つあって

1-1、User-Agentをどうやってスマフォ用、PC用と判別させるのかという問題点があり、正規表現等を駆使すればかけそうには思うのですが、なにぶんUser-Agentは様々な種類があり、また全てのブラウザでアクセスするわけにもいきません。
そのためバグがあっても気づかない可能性が高いです。
そこでなにかいい判別方法ないしは、モジュール等はないでしょうか?

1-2、User-Agentをスマフォ用に判別することに成功したとして、その結果をどのように扱うという問題があります。
といいますのも、現在は「UserAgent毎*URL毎」にキャッシュをとっていますが、これを「(PC or UserAgent) * URL毎」にしたいのです。
しかしこういう機能をどうやって、mod_cacheで実現すればいいのでしょうか?

2、サイトにアクセスしてみるとなぜかResponseにVary:Accept-Encodingが指定されています。これがあると、mod_cacheがUser-Agentではなく、Accet-Encoding単位でキャッシュを作ってしまい、PCとスマフォのキャッシュがごちゃごちゃになってしまいます。

Develop環境のローカルのRailsサイトではついてない事は確認してるのですが、どこでつけられたのでしょうか?
またいくつかのサイトを見てみると、このVaryがよく指定されています(例えばこのサイトとか)。なぜこのVaryを指定しているのでしょうか?

長くなりましたが、質問の一部でもご回答いただけると助かります。

  • UserAgent をチェックする。結果:
    Android が入っていたら Android、
    iPhone が入っていたら iPhone、
    それ以外だったら PCとする。でいいんじゃ?

    -
  • 追記 mod_rewrite と連携ね -
  • お返事ありがとうございます。それはつまり、varyは空にして、User-AgentでスマフォかPCを識別。その後mod_rewriteによってpc/hoge,mobile/hogeみたいなURLに内部でリダイレクトをかけ、そのURLを元にキャッシュする。
    ということですか?
    -
  • mod_rewrite を利用して setenv/setenvif ( ex. appname="android" ) してその値を vary に設定する。 UserAgent で分離できるならこの方法でもいけるはず。 -
  • おつきあいありがとうございます。varyにその値を設定するというのは、Responseのヘッダにvary: appnameとつける。そしてApacheの内部でRequestヘッダにたいしてappname:android を付与するということですか? -

回答

自己解決しました。

Apacheではキャッシュのキーを自分では設定できまんせが、Nginxではキーを自由に設定できます。
またNginxはキャッシュを生成するさいにCache-Controlは見ますがVaryは無視します。

そこでNginxをApacheのキャッシュプロキシサーバーにして、Nginxでキャッシュを返し、キャッシュが無い場合はApache+Railsにリクエストを投げる様にしました。

この際に注意点として、Cache-Controlがmax-age=60みたいな有効になっていると、mod_cacheを入れてなくてもApacheがキャッシュをしてしまうため、Rails->ApacheはCache-Controlを有効にしない。Apache->NginxではCache-Controlを有効にすることで、Nginxだけにキャッシュを持たせる様にしました。ここは少し強引だと思っており、何か解決策があればご教授いただけると幸いです。

お騒がして申し訳ありませんでした。

編集 履歴 (0)
ウォッチ

この質問への回答やコメントをメールでお知らせします。