A Day in the Life

さいきんの Rails サービスを高速化をしてみた

先日のももクロハッカソンで出会った wantedly を作ってる仲さんが

と言ってたので、面白そうなので wantedly を速くしてみました。

ちなみにデータが数百万オーダーもなさそうなのに、どのページもログインすると2-5秒ぐらいかかっていたので、確実に速くできそうだなぁという感覚はやる前からありました。

アプリケーションサイドのチューニング

初心者*1にありがちな問題として

  • SQL に適切にインデックス張ってない
  • キャッシュすべき場所をキャッシュしていない
  • 無駄なデータを引きすぎてる

ことがよくあります。ので順に実装を見ていきました。

SQLに適切なインデックスを張ってない

張ってありました!びっくり!\(^o^)/

キャッシュすべき場所をキャッシュしていない

Facebook API を利用したアプリケーションなんですが、ユーザのデータの取得を毎回馬鹿正直に HTTP を叩いてとっていたため、適切にキャッシュを入れました。これで1秒強ぐらい速くなりました。

無駄なデータを引きすぎている

うっかり全件データ(!) を引いていたり、引かなくて良いデータを引いていたり箇所をログと New Relic *2から見ていって直していきました。これでログインユーザが1-3秒ぐらい速くなりました。
SQL のインデックス張ってない問題やこれの問題は、データが少ない当初は遅いと感じなくても、データが増えれば増えるほど徐々に重くなっていき、また開発環境では本番と異なるデータを使ってるため、データ量が少ないこともあるため、初心者には気づきにくい & どこを直したら良いか解らないといったことが発生しがちでしょう。

結果

約6倍速\(^o^)/

体感速度のチューニング

続いてユーザが実際に感じる速度を向上させました。

wantedly は heroku にあるためサーバが遠く、1ファイルの取得に 200ms-300ms のタイムラグが発生します。そのため、以下のアプローチをとりました。

リダイレクトは極力減らす

リダイレクトするとそれだけで200-300ms遅く感じてしまうため、よくクリックするリンクはリダイレクトで無く、URL の生成でちゃんとリダイレクト先を生成するように変更しました。

静的ファイルをまとめる

Rails 3.1 からは 3.1 の目玉機能の一つ、asset pipeline が利用できるようになり、何も考えなくともルールに従えば js / css ファイルを一つにまとめられるようになったため、Rails 3.0 系から Rails 3.1.0 にアップグレードして asset pipeline を有効化しました。なお Rails 3.1.0 化はコード上 Rails 本体を弄る等無理な書き方をしてなかったため、割とすんなりアップグレードできました。

なお、heroku で asset pipeline をうまく使うには memcached plugin を入れ

# production.rb
  config.serve_static_assets = true
  config.assets.compress = true
  config.assets.compile = true

と設定するとうまく動くと思います。

静的ファイルをブラウザにキャッシュさせる

いわゆる Expires / Cache-Control ヘッダの指定ですね。Rails 3.1 + Asset Pipipele + Heroku でうまくキャッシュさせるには

config.assets.digest = true

で asset の URL が内容が変更があったら変わるようにし(じゃないとキャッシュされ続けるため)

config.static_cache_control = "public, max-age=#{1.day}"

で、Rack の ActionDispatch::Static で Cache-Controle ヘッダをはかせるようにします。

結果

以前

以後

ちょっとわかりにくいですが、青のラインが250msぐらい速くなり、体感的にもロードが速くなりました。特に Heroku のようなサーバが遠い場合は効果がだいぶ出ると思います。

終わりに

これ以上の高速化には国内のサーバにする & 動的では無いコンテンツにフロントでもう一段階ちゃんと Varnish 等を入れキャッシュ設計するが必要になりますが、それをするのはコストがかかりすぎるので、やるとしてもサービスがだいぶ伸びてからになると感じました。

あとよく Rails アプリ遅いと言われてますが、200ms 前後の速度でしたらサービスがだいぶ大きくならない限りは、Heroku 等の PaaS でも簡単に維持できるなぁと改めて感じました。*3

あとあと、初めてちゃんと Heroku 触ってみたんですがすごく良くできてますね。ただやっぱり太平洋超えるのは日本向けのサービスだとするとつらいなー、とも感じたので Heroku の ec2 の東京リージョン版が出たらより日本でも流行りそうですね〜。

*1:仲さんはプログラミング初めて一年、Rails 初めて数ヶ月ですが、Ruby の実装から html / css / js ほぼすべて一人で wantedly 作ってすごい…

*2:Heroku 無料で New Relic プラグインが使えて便利

*3:200ms だと遅いという方も居ると思いますが、だいたい重いと感じるサービスはもっともっと処理コストがかかってると思うので…

記事の一覧 >

関連するかもエントリー

Ruby on Rails が簡単というのはウソ
Ruby on Rails が簡単というのはウソ綺麗に手順を踏んでやる場合には Ruby 初心者は躓くところが多い && 最初の学習コスト高いというのは納得。なおWebエンジニアの場合、こんな感じなのかな。たぶん。Windows だといろいろうまくいかないので Mac 買う or...
Ruby on Rails が簡単というのはウソ綺麗に手順を踏んでやる場合には Ruby 初心者は躓くところが多い && 最初の学習コスト高...
Rails3レシピブック 190の技を読んだ
Rails3レシピブック 190の技を読んだ読みました。僕は Rails 2.0 世代からいきなり 3.0 をやり始めて、特に routing 周りの変更でだいぶ困ってたんだけど読んですっきり。もっと早く読みたかった!!旧世代(Rails 1,2)から Rails 3 やろうと思...
Rails3レシピブック 190の技を読んだ読みました。僕は Rails 2.0 世代からいきなり 3.0 をやり始めて、特に routin...
ActiveSupport の Cache Store に Null が無い
ActiveSupport の Cache Store に Null が無い何にもキャッシュしない API 無いのなんでですか〜。とりあえずActiveSupport::Cache::MemoryStore.new(:size => 0)でキャッシュされないけどAPIは持ってるイ...
ActiveSupport の Cache Store に Null が無い何にもキャッシュしない API 無いのなんでですか〜。とりあえず...