QA@IT

Railsで作ったサービスの速度改善方法について教えて下さい

11404 PV

この度、弊社が運営しているRailsで開発したサービス(会員数20万程度の規模のサービス)の速度改善を行うことになりました。
もし、同様のサービスにおいて速度改善に知見がある方がおりましたら、
ご助言頂けないでしょうか。
varnishやmemchacedといったサーバーの環境設定、
Railsのscopeやrenderのパフォーマンスの良い記述方法などを、
教えて頂けたら幸いです。

以下、開発環境になります。

  • 言語:Ruby1.9.2
  • フレームワーク:Rails3
  • DB:MySQL
  • サーバー:APPサーバー4台/バッチサーバー1台/varnishサーバー1台
  • バージョン管理ツール:git
  • デプロイ手段:capstrano

補足:
フロントエンドにおいての速度改善の施策については着手中です。
今回はサーバサイドにおいての速度改善でアドバイスを頂きたいです。

回答

会員数3000万程度の規模のサービスを運営しているものです。

まずは http://newrelic.com の無料版を導入してみれば、ありとあらゆるボトルネックが見つかって改善できると思います。

また、ruby 1.9.2は起動がすごく遅いですしGCの性能にも偏りがあるので、これを最低でも1.9.3できれば2.0.0に上げるだけでタダで性能改善すると思います。

この辺りの話はクックパッドのレポートにもありますね。

http://techlife.cookpad.com/2013/04/09/ruby200/

デプロイの前後でどれだけ改善したかをリアルタイムに確認するのにも上記New Relicは有用です。

memcacheで気をつけたいのはフラグメンテーションです。slabsの統計をみて効率よく使われているかを確認します。最近のバージョンでは改善されていますが、1GBあるつもりが実効300MBぐらいしか使えておらず想定以上にLRUでevictされてmemcacheなしよりも実は遅くなっていた、ということが往々にしてあります。

というのも、現代的なテクノロジースタックで一番遅いのはネットワークのラウンドトリップ(0.1-0.5ms程度)なので、memcacheサーバを叩くステップを増やしてキャッシュヒットさせるよりMySQL直で読ませたほうが実は速い、なんてことはざらにあります。そもそもMySQL自体がキャッシュのおばけですから、何をmemcache化するか、というのは思い込みではなくてきちんと実証していく必要があります。

個人的な経験でいうと、memcacheの使いドコロは計算コストの高い巨大なHTMLテンプレートのレンダリングした結果など比較的大きな演算結果のキャッシュですが、JSON APIなどを多用する現代的なスタックではほぼ出番がありません。

varnishはOSのファイルシステムのバッファキャッシュを使える分だけ、はまるところでは良いのでしょうが、大規模なシステムでの導入経験がないのでコメントできるだけの知識がないです。

で、この構成で性能を考える上で何よりも大事なのはMySQLですが、実はMySQLのチューニングは簡単です。あまり考えずに

innodb_buffer_pool_size = 搭載メモリの70-80%程度
innodb_log_file_size = 100-500MB程度(更新性能とクラッシュリカバリ時間のトレードオフ)
innodb_flush_log_at_trx_commit = 2

の3つだけ、きちんと設定すれば、カリカリにチューニングした場合の8割ぐらいの性能は出ると考えて良いです。(innodb_log_file_sizeの設定変更には色々罠があるのでググってください)

編集 履歴 (0)
  • コメントありがとうございます。
    詳細かつ、分かりやすくまとめられていて大変、参考になりました。
    頂いたコメントを元にテスト環境でのRubyバージョンアップや、
    MySQLのチューニングを行います。
    実施後はこちらにて結果を書きたいと思います。
    -

kennさん
お答え頂いた内容を参考に現時点での対応を以下に纏めました。
①New relicの導入
 (ymlの罠(デフォルトは設定反映がfalseになっていた)で少し詰まりました)
②スロークエリから遅いSQLを特定、特定箇所のロジックを変更
 (scopeの連結が多いところをsql直書きする。不要なJOINの削除。
 Arel tableを導入しようかと思いましたが現時点では速度改善ができて即導入、
 テストが出来るという点でsql直書きを選択)
③my.cnfの設定を変更
(innodb_buffer_pool_sizeを変更)

RubyのバージョンアップやRailsのバージョンアップはbundleでこけたり、
gem install中に落ちるといったことがあったため、
もう少しテストが必要です。

これからも継続的に改善していきます。
本当にご助言、ありがとうございます。

 

編集 履歴 (0)

コメントありがとうございます。
詳細かつ、分かりやすくまとめられていて大変、参考になりました。
頂いたコメントを元にテスト環境でのRubyバージョンアップや、
MySQLのチューニングを行います。
実施後はこちらにて結果を書きたいと思います。

編集 履歴 (0)
ウォッチ

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