Web + Life Hack

〜True But Useless〜

【Ruby】【Rails】へっぽこエンジニアがfragment cacheでハマって解決するまでの紆余曲折まとめ



弊社で請け負った開発の納品前に
速度に問題があるということで
急遽、キャッシュを導入することになりました。
今回はRails4でキャッシュ導入で悪戦苦闘した一部始終をご覧ください。

前提条件:
Ruby/Rails

g08m11$ ruby -v
ruby 2.0.0p247 (2013-06-27 revision 41674) [x86_64-darwin12.3.0]

g08m11$ rails -v
Rails 4.0.3


1・アクションキャッシュを使おうとしてハマった。

そもそもフラグメントキャッシュを導入する前は
アクションキャッシュを導入しようと考えていました。
Rails4だとRails3と違いデフォルトでは使えないので、
actionpack-page_caching」を

gem 'actionpack-page_caching'


とGemファイルに記述してbundle install、gem updateを実施し、
Rails3同様に利用しよう

と思ったのですが。。。

導入したアクションはシンプルなアクションでは無く、
javaScriptJQueryを多く利用しているアクションであったため、
導入すると挙動がおかしくなり
(動いてたはずのjsが動かない。レスポンスが激悪など多数)
結果、導入をあきらめました。


2・fragmentキャッシュを導入したがキー値が良く分からずハマった。

上記1がうまくいかなかったので、fragment cache

<% cache do %>
<% end %>

を「キー値を設定しないまま」導入してみましたが、
「キー値が未設定な状態」だと同じキャッシュでもRails側がキー値を一意に設定してしまい、

キャッシュが失効していたと思ったら新しいキーが生成されてずっと残ってる

という状態になっており、挙動がつかめずハマりました。
トリッキーな使い方をしないのであれば

<% cache 'キー値', skip_digest: true do  %>
<% end %>

としてキー値をRails側で生成させないようにした方が無難です。


3・「unless cache.exist?」でハマった。

キャッシュを使うのであればそのキャッシュが無い場合のみActiveRecordの実行や
インスタンス生成などを行うことでより表示速度を向上させようと考えたのですが、

削除したキャッシュを見ようとしたり、

挙動がおかしくて利用することを諦めました。

4・キャッシュ変更時にUnicornを再起動しなかったためハマった。

動作確認で用いたキャッシュを削除したのですがログ上ではまだ残っているなど
挙動が安定しなかったところ、Unicorn再起動で正常に戻りました。


5・共有ブランチのdevelopment.rbを変更したため周りに迷惑を掛けた。

デフォルトだとキャッシュを有効にする設定が

 config.action_controller.perform_caching = false

となっているのですが、それを

 config.action_controller.perform_caching = true

としてしまったため、
他メンバのローカル環境で挙動がおかしくなってしまい、迷惑を掛けてしまいました。



6・失効するタイミングが分からずハマった。

元々、失効する所まで意識できていなかったことが問題なのですが、
ログを見て「キャッシュの書き込み、読み込みが行われることの確認」だけになっていました。
しっかり失効も出来なければキャッシュを自由に扱うことができないということで、
コントロール側に

 expire_fragment('失効したいキャッシュのキー値')

を書く必要があります。
またcreate、updateなど複数のタイミングかつ複数のキャッシュを失効したい場合は

after_action :cache_expire, only: [:create,:update]

とし、

  def cache_expire

    #検索部分のselectボックスのキャッシュ失効
    expire_fragment('g08m11_1')
    expire_fragment('g08m11_2')

  end

とすると冗長的な記述が減って便利です。

そんな紆余曲折があった中、どれほどの結果があったかというと、


layouts/g08m11_1.html.erbの場合

キャッシュ未設定
[2014-02-26 21:45:54.811002 #27622][ INFO] -- : Rendered layouts/g08m11_1.html.erb (399.9ms)
[2014-02-26 21:46:01.783627 #27657][ INFO] -- : Rendered layouts/g08m11_1.html.erb (380.9ms)
[2014-02-26 21:48:40.517840 #27641][ INFO] -- : Rendered layouts/g08m11_1.html.erb (460.5ms)
[2014-02-26 21:48:54.046263 #27557][ INFO] -- : Rendered layouts/g08m11_1.html.erb (370.4ms)
[2014-02-26 22:50:28.992918 #3255][ INFO] -- : Rendered layouts/g08m11_1.html.erb (442.9ms)


キャッシュ設定、読み込み後
[2014-02-27 12:20:09.794757 #25910][ INFO] -- : Rendered layouts/g08m11_1.html.erb (35.9ms)
[2014-02-27 12:20:21.565874 #25876][ INFO] -- : Rendered layouts/g08m11_1.html.erb (34.2ms)
[2014-02-27 12:20:29.364536 #25885][ INFO] -- : Rendered layouts/g08m11_1.html.erb (33.3ms)
[2014-02-27 12:20:56.428025 #25931][ INFO] -- : Rendered layouts/g08m11_1.html.erb (34.6ms)
[2014-02-27 12:21:10.860242 #25960][ INFO] -- : Rendered layouts/g08m11_1.html.erb (12.0ms)



layouts/g08m11_2.html.erbの場合

キャッシュ未設定
[2014-02-27 19:19:19.507540 #2300][ INFO] -- : Rendered  Rendered layouts/g08m11_2.html.erb (55.0ms)
[2014-02-27 19:45:53.916644 #4642][ INFO] -- : Rendered  Rendered layouts/g08m11_2.html.erb (70.8ms)
[2014-02-27 19:56:45.174720 #7787][ INFO] -- : Rendered  Rendered layouts/g08m11_2.html.erb (102.9ms)
キャッシュ設定、読み込み後
[2014-02-27 20:03:29.623759 #9582][ INFO] -- :  Rendered layouts/g08m11_2.html.erb (6.1ms)
[2014-02-27 20:03:40.535835 #9516][ INFO] -- :  Rendered layouts/g08m11_2.html.erb (4.5ms)
[2014-02-27 20:03:55.237033 #9527][ INFO] -- :  Rendered layouts/g08m11_2.html.erb (0.8ms)


といったように

g08m11_1.html.erbだと表示速度を最大1/37に短縮
g08m11_2.html.erbだと表示速度を最大1/128に短縮



することが出来ました。
用途は限定的になってしまいますが、
「Redis」も「memcached」を使う前に
「fragment cache」を利用してみてはいかかがでしょうか?


追伸:
今回のfragment cache以外にも
サーバスペックを上げる、
AWSインスタンスを「m3.large」にする)
MySQLの設定を最適化する、
AWSのRDSを使ったので簡単に設定を最適化にした)
といったことも行っています!

告知

現在、私はmoreiという団体を設立し「Sweet Swift」という女性限定iOSプログラミング講座を開催しております。

アプリが作りたいと考えている方やプログラミング始めたいという方が

おりましたらぜひお誘いの上、ご参加ください!

(女性の方限定となります。ご了承ください。)

直近の開催日時などは以下のとおりです。

10/1(木) 20:00〜22:30@Viibar様(目黒駅近く)

morei.doorkeeper.jp

10/17(土) 14:00〜16:30@Lib様(渋谷駅近く)

morei.doorkeeper.jp

11/06(金) 18:45〜21:00@ファンコミュニケーションズ様(渋谷駅近く)

morei.doorkeeper.jp

11/18(水) 20:00〜22:30@メンバーズキャリア様(月島駅近く)

morei.doorkeeper.jp

12/3(木) 20:00〜22:30@ナイル株式会社様(五反田駅近く)

morei.doorkeeper.jp

アプリを学びつつ、Web系会社の雰囲気も感じられる機会になるかと思いますので

ご参加お待ちしております!