-
Notifications
You must be signed in to change notification settings - Fork 9
rack cache memcached static assets rails31
少し複雑になりますけど、静的アセットを供給するためには、CDNを使用することが最も効率的なオプションとなります。 詳細はこちらの記事を参照して下さい。 CDN asset host
Ruby on Railsのアプリケーションでは、Cedar stack上にアセットを効率的に供給するために Rack::Cacheを使うべきです。 適切なRack::Cacheの使用は、レスポンスタイムを改善し、ロードを減らし、アプリケーションを通して静的アセットを 供給する際に重要となります。
この記事は、Rack::Cacheを使ったキャッシュのアセットの概念についてサマライズしています。 また、Rails 3.1のアプリケーションとアセットパイプラインの適切な設定に関しても、手順を示します。
この記事で参照するアプリケーションのサンプルコードは、 GitHub上に置かれており、 http://rack-cache-demo.herokuapp.com/で 動作を確認することが出来ます。
Rack::Cacheは、Rackのミドルウェアで、アプリケーションに対し、HTTPのキャッシュを 可能とし、メインのRailsアプリケーションからワークを獲得すること無しに、バックエンドのストレージからアセットを供給することを アプリケーションに対し許可します。
ミドルウェアと呼ばれる、リクエストを得て、それをステップの連続でパスすることにより、Rackは高いレベルで動作します。 それぞれのRackミドルウェアは、いくつかのアクションを実行し、それからRack内の次のミドルウェアへリクエストをパスします。 最終的にはリクエストは適切にフォーマットされ、アプリケーションに返されます。
Rackは、軽量かつ柔軟に記述されます。もしミドルウェアが、直接、リクエストに対しレスポンス出来るのであれば、 Railsアプリケーションへアクセスする必要はありません。これは、リクエストがより早く返され、Railsアプリケーションの 全体のロードを減らすことを意味します。
Rack::Cacheは、2つの異なるストレージ領域を持っています。: metaとentityのストアです。 metaストアは、HTTPリクエストとレスポンスヘッダーを含む、それぞれのキャッシュに関する高度なレベルの情報を格納します。 この領域は、高頻度でアクセスされる小さな塊のデータを格納します。 entityストアは、metaストアよりはアクセス頻度が下がるものの、比較的大きめのデータ量となるbodyの中身を格納します。
Rack::Cacheは、3つの異なるストレージエンジンを提供します。: file
、heap
、memcache
です。
file
エンジンの格納データは、低速なものの、メモリ効率は良いです。
heap
エンジンを使うことは、プロセスメモリをより高速に使えるものの、無制限にプロセスメモリが増え続けるのであれば、
パフォーマンスに大きな影響を与えます。
memcache
エンジンを使うことは、多数のオブジェクトを格納するには適さないものの、最も高速な手段となります。
memcache
エンジンでmetaストアを使うことは、共有されるmetaデータへ高速なアクセスが可能となることを意味します。
file
エンジンでentityストアとより多くのオブジェクトを扱うという選択肢もあるものの、
効率的で予測可能なパフォーマンスを発揮し、Herokuでは推奨されています。
アプリケーションをローカルで実行し、Rack::Cacheをテストするために、Memcacheをインストールする必要があります。 Mac OSXでは、homebrewのようなツールを使用することで、インストール可能です。
:::term
$ brew install memcached
homebrewでのインストールの最後に、システム起動時にMemcacheをマニュアルでスタートさせるか、自動でスタートさせるかの インストラクションが表示されます。
Herokuでは、Memcacheと一緒に、Rack::Cache
のバックエンドとして
Dalliというgemを使用することを推奨しています。
Gemfile
へ下記を追加して下さい。:
:::ruby
gem 'dalli'
Dalliのアプリケーション依存関係を確立するためにbundle install
を実行した後、
config/application.rb
内の下記を修正することで、RailsへDalliをキャッシュストアとして使うことを伝えます。
:::ruby
config.cache_store = :dalli_store
ローカルのRailsコンソールを起動し、シンプルなKey-Valueのセット/ゲットをすることで、 Dalli/Memcacheの設定を確定して下さい。
:::term
$ rails c
> memcache = Dalli::Client.new
> memcache.set('foo', 'bar')
> memcache.get('foo')
'bar'
Memcacheを使うためのアプリケーション設定が完了しますと、次は、Rack::Cacheを設定することとなります。
ビルトインされたRailsのRack::Cacheへ、適切なストレージのバックエンドを明示するため、
config/environments/production.rb
の環境設定ファイルを修正して下さい。
:::ruby
config.action_dispatch.rack_cache = {
:metastore => Dalli::Client.new,
:entitystore => 'file:tmp/cache/rack/body',
:allow_reload => false
}
仮に明示しなかった場合、`Dalli::Client.new`は自動的に`MEMCACHE_SERVERS`環境変数からMemcacheサーバの場所を 検索します。環境変数から取得出来なければ、localhostと初期ポートをデフォルトとします。
アプリケーションが適切に、静的アセットを供給、無効、リフレッシュ出来るように、config/environments/production.rb
内の
いくつかのコンフィグを更新する必要があります。
serve_static_assets
の設定を行うことで、Railsが静的アセットを供給出来るよう許可して下さい。
:::ruby
config.serve_static_assets = true
さらに、Cache-Controlヘッダーを設定することで、アイテムがどのくらいの期間キャッシュされるかを明示して下さい。
Cache-Controlヘッダーの設定無しに、静的ファイルがRack::Cache
によりストアされることはありません。
:::ruby
config.static_cache_control = "public, max-age=2592000"
これらの設定は、Rack::Cache
がとても長い時間、静的な要素をストアすることを意味します。
変更されたファイルのキャッシュを適切に無効化するために、Railsはファイル名のハッシュダイジェストを更新します。
config.assets.digest
を設定することで、この動作を可能とします。
:::ruby
config.assets.digest = true
本番環境でもこのキャッシュ設定を有効としたいでしょう。下記の設定を行って下さい。
:::ruby
config.action_controller.perform_caching = true
Rack::Cache
のmetaストアとして、Memcacheを使うでしょうから、
Memcacheアドオン をHeroku上のアプリケーションへ追加する必要があります。
:::term
$ heroku addons:add memcache
----> Adding memcache to myapp... done, v25 (free)
アプリケーションをHerokuへディプロイし、キャッシュの結果を見るために、heroku logs
コマンドを実行して下さい。
:::term
$ git push heroku master
$ heroku logs --ps web -t
沢山あるログの中からcache
エントリを参照して下さい。
miss, store
は、対象のアイテムがキャッシュ内に見つからなかったものの、次回リクエスト時のために保存されたことを示唆しています。
:::term
cache: [GET /assets/application-95bd4fe1de99c1cd91ec8e6f348a44bd.css] miss, store
cache: [GET /assets/application-95fca227f3857c8ac9e7ba4ffed80386.js] miss, store
cache: [GET /assets/rails-782b548cc1ba7f898cdad2d9eb8420d2.png] miss, store
fresh
は、対象のアイテムがキャッシュ内に見つかり、キャッシュから供給されることを示唆しています。
:::term
cache: [GET /assets/application-95bd4fe1de99c1cd91ec8e6f348a44bd.css] fresh
cache: [GET /assets/application-95fca227f3857c8ac9e7ba4ffed80386.js] fresh
cache: [GET /assets/rails-782b548cc1ba7f898cdad2d9eb8420d2.png] fresh
これで、あなたのRails 3.1+のアプリケーションが、Memcacheを使い、ダイナミックなアプリケーションのリクエストを 実現させるためにdynosを有効活用し、静的アセットをキャッシュするよう設定されたこととなります。
もし設定が適切になされていないと、store
やfresh
の代わりに、miss
を見ることになります。
:::term
cache: [GET /assets/application-95bd4fe1de99c1cd91ec8e6f348a44bd.css] miss
cache: [GET /assets/application-95fca227f3857c8ac9e7ba4ffed80386.js] miss
cache: [GET /assets/rails-782b548cc1ba7f898cdad2d9eb8420d2.png] miss
この現象が発生した場合、アセットのレスポンスヘッダーを検査するために、curl
を使い、
Cache-Controlヘッダーが存在していることを確実にします。
:::term
$ curl -I 'http://rack-cache-demo.herokuapp.com/assets/shipit-72351bb81da0eca408d9bd8342f1b972.jpg'
HTTP/1.1 200 OK
Age: 632
Cache-Control: public, max-age=2592000
Content-length: 70522
Etag: "72351bb81da0eca408d9bd8342f1b972"
Last-Modified: Sun, 25 Mar 2012 01:51:21 GMT
X-Rack-Cache: fresh
レスポンスヘッダーは、Cache-Control
を含んでいるべきであり、config.static_cache_control
内に設定した
詳細な値(例えば、public, max-age=2592000
)を返すべきです。
また、アセットの状態(fresh/store/miss)を示すX-Rack-Cache
ヘッダーが表示されているかを確認して下さい。
もし、予期せぬ結果が表示されているのであれば、本番環境の設定を確認して下さい。
thinをwebサーバーとして使用する場合、Rack::Cache
の設定が適切になされているかを
Procfile内の開始位置に$RACK_ENV
を渡すことで確認して下さい。
web: bundle exec rails server thin -p $PORT -e $RACK_ENV
もし、ファイルを変更したにも関わらず、サーバーが古いファイルを返し続ける場合、ディプロイする前に、
Gitのリポジトリにコミットされているかを確認して下さい。
ファイルがコンパイル済みのコードに存在するかは、heroku run bash
コマンドを実行し、
public/assets
ディレクトリの中身を見ることで確認可能です。
このディレクトリは、ハッシュ化されたファイル名のアセットを管理しています。
:::term
$ heroku run bash
Running bash attached to terminal... up, run.1
$ ls public/assets
application-95bd4fe1de99c1cd91ec8e6f348a44bd.css application.css manifest.yml
application-95bd4fe1de99c1cd91ec8e6f348a44bd.css.gz application.css.gz rails-782b548cc1ba7f898cdad2d9eb8420d2.png
application-95fca227f3857c8ac9e7ba4ffed80386.js application.js rails.png
application-95fca227f3857c8ac9e7ba4ffed80386.js.gz application.js.gz
また、ファイルがRailsのmanifest.yml
にリストされていることを確認して下さい。
:::term
$ cat public/assets/manifest.yml
rails.png: rails-782b548cc1ba7f898cdad2d9eb8420d2.png
application.js: application-95fca227f3857c8ac9e7ba4ffed80386.js
application.css: application-95bd4fe1de99c1cd91ec8e6f348a44bd.css
もし、探しているファイルが見つからないのであれば、ローカルでbundle exec rake assets:precompile RAILS_ENV=production
を
実行し、public/assets
ディレクトリにファイルが存在していることを確認して下さい。