酒と泪とRubyとRailsと

Ruby on Rails と Objective-C は酒の肴です!

[Rails 高速化] ページキャッシュ、N+1対策、SQLチューニング

Cookpadではユーザーへのレスポンスタイム 200ms/reqを目標にしている』に感銘を受けて書き始めたこの記事ですが、『パフォーマンス・チューニングやオススメGem in 「Rails勉強会@東京 第88回」』で色々教えてもらったり、最近関わっているサイトのリニュアールで試行錯誤したので、忘備録も兼ねて記事をアップデートします!


Included file ‘custom/google_ads_yoko_naga.html’ not found in _includes directory

目次

(1) N+1問題の対策
(2) Railsのキャッシュについて
(3) 開発中ならrack_mini_profiler
(4) 運用中なら断然NewRelicがおすすめ
(5) mysqlの簡単チューニング

(1) N + 1問題の対策 Gem Bullet

Bulletの導入手順

RailsのActiveRecord(findやwhere)は便利ですが、DB(SQL)の側から見ると非効率的なクエリを発生させることがあるようです。これを監視して警告を出してくれることで有名なGemが『Bullet』です。

まずは、bulletをインストールします。Gemfileに以下を追記してbundle installを実行。

1
2
3
4
group :development do
  # N+1問題の警告を出力
  gem "bullet"
end

続いてconfig/environments/development.rbに以下を追記。

1
2
3
4
5
6
7
8
9
AppName::Application.configure do
  config.after_initialize do
    Bullet.enable = true # Bulletプラグインを有効
    Bullet.alert = true # JavaScriptでの通知
    Bullet.bullet_logger = true # log/bullet.logへの出力
    Bullet.console = true # ブラウザのコンソールログに記録
    Bullet.rails_logger = true # Railsログに出力
  end
end

これでブラウザで開発サイトを普通に閲覧していると、N+1問題が発生するページではアラートを出してくれるようになります。

複数のテーブルを含むincludesについて

Bulletでは関連テーブルを呼び出すようなSQLを検知した場合に、複数のテーブルを含むincludesをするようにアラートが出ます。例えば、ブログ(Blog)に記事(Articles)があり記事に複数の画像(Images)があるようなモデルを考えます。

Blog => Articles => Images

この場合には、ActiveRecordで以下のようなコードを書けば複数テーブルを含むincludesを指定できます。

1
Blog.includes(articles: [:images])

頭のなかだけで考えただけなので、間違っている可能性もありますが、このようにHash&Array&Symbolでうまく呼び出してあげる必要があります。こちらの記事『【Ruby On Rails3】 複数のテーブルのincludesを書く! | approad』を参考にさせていただき、うまく組むことが出来ました!

(2) Railsのキャッシュについて

フラグメントキャッシュ(RussianDollCaching)

Rails4になって、メインのキャッシュ機能は『フラグメントキャッシュ(RussianDollCaching)』になったようです。

http://o.inchiki.jp/obbr/201

フラグメントキャッシュの詳細な説明は、『Rils4で Russian Doll Caching を楽しむためのまとめ [俺の備忘録]』がわかりやすくておすすめです!

ちなみに、恥ずかしながら最近フラグメントキャッシュを使うようになりましたが、cache modelid-updated_atという情報を付加してくれます。(modelに変更があったら自動的にキャッシュがアップデートされます)かなり気に入っています^^

ページキャッシュについて

Rails4からは、ページキャッシュは別のgem『rails/actionpack-page_caching』として提供されるようになったようです。

http://www.rubytutorial.io/page-caching-with-rails-4

こちらの記事『Page caching with Rails 4』は英語ですが、シンプルでわかりやすい説明です。ページキャッシュはRailsを介さずにApacheと直接やりとりができるため、レスポンスが高速になるので、もし使いやすいサイトであれば積極的にトライしてみるのもありだと思います!

Included file ‘custom/google_ads_yoko_naga.html’ not found in _includes directory

(3) 開発中ならrack_mini_profiler

現状、Railsのプロファイラーで一番メジャーなのは、『MiniProfiler/rack-mini-profiler』です。

ViewのレンダリングやActiveRecordの問い合わせにかかっている時間などを計測して教えてくれます。

導入方法も至って簡単です!Gemfileに以下のコードを追加して、コマンドラインでbundle installを実行。

1
gem 'rack-mini-profiler'

あとは、ブラウザで開発サイトを普通に閲覧していると、小さく速度を計測して表示してくれるようになります。ドリルダウンで詳細な問い合わせ内容もすぐにわかってボトルネックの部分を調べることができます!

(4) 運用中なら断然NewRelicがおすすめ

http://www.engineyard.co.jp/blog/2013/new-relic-night/

実運用中のサイトのチェックであればNewRelicがやはりおすすめです。上のサイトは去年開催された『New Relic Nightを開催しました。(動画&スライド)』の内容です。運用ノウハウのつまったスライドが多数あります。

以前『Rails勉強会@東京 第88回』に参加させて頂いた際にも次のようなメリットがあるというのを教えていただきました!

* アプリケーションの監視に最適なツール
* アクション => メソッド、sqlが遅いまでチェックできる
* アクションをひとつひとつチェック => 定義・構造がおかしいか探す => レンダリングの改善
* サイト全体平均より、重要なページを計測して改善をすべき
* js側のチェックも出来る

(5) MySQLの簡単チューニング

Railsで作ったサービスの速度改善方法について教えて下さい - QA@ITの中にあるMySQLの簡単なチューニングをやってみたところ、僕の環境でも体感で速度が改善しました。

まず、vim my.cnfの中の以下の設定を変更します。

1
2
3
innodb_buffer_pool_size = # サーバのメモリ70〜80%
innodb_log_file_size = # 100-500MB程度
innodb_flush_log_at_trx_commit = 2

次にMySQLの

innodb_log_file_size
を変更するために、mysqlにログインして以下のコマンドを実行します。

1
mysql> SET GLOBAL innodb_fast_shutdown=0;

次にmysqlをストップします。

1
2
/etc/init.d/mysqld stop
# mac/homebrewの場合は、mysql.server stop

そしてトランザクションファイルを削除(もしくは移動)。

1
2
3
4
5
rm /var/lib/mysql/ib_logfile0
rm /var/lib/mysql/ib_logfile1
# mac/hoebrewの場合のデフォルトは:
# rm /usr/local/var/mysql/ib_logfile0
# rm /usr/local/var/mysql/ib_logfile1

MySQLを起動します。

1
2
 /etc/init.d/mysqld start #
mac/homebrewの場合は、mysql.server start

トランザクションログファイルが作成されていれば成功です。

Included file ‘custom/google_ads_yoko_naga.html’ not found in _includes directory

Special Thanks

N+1問題などを監視してパフォーマンスを改善するRailsプラグインBullet|WEBデザイン Tips

Railsの画面生成を10倍高速化する方法 - 世界線航跡蔵

MySQLの「innodb_buffer_pool_size」と「innodb_log_file_size」の設定 – FlatLabs

変更来歴

13/04/17 10:00 Bulletの仕様変更により、development.rbの設定を変更
13/05/20 17:35 mysqlの簡単チューニングを追加
14/01/26 19:05 試行錯誤した結果に基づいていくつか書き直し

おすすめの書籍