第4回チューニンガソンで8位になりました。 #tuningathon

f:id:yosuke_furukawa:20120701202534p:plain

ずっと前から出てみたかったチューニンガソンに出ることができました。
第4弾! いろいろチューニングしてパフォーマンスを競うバトルイベント「チューニンガソン」7月1日(日) 開催! #tuningathon on Zusaar

今回はそのチューニンガソンの雰囲気とせっかく8位になったので、自分がやったチューニングのポイントをかいつまんで説明します。

第四回チューニンガソンのルール


測定方法

  1. Ruby on Rails の refinery CMSのコメントPOST/GET回数を10並列で一定秒数間測定。
  2. 秒間平均POST/GET回数がスコア
  3. POSTはGETの10倍のスコア
  4. POST後のGETによる反映チェック
  5. 反映チェックの成功率の二乗をスコアに乗算

POSTはGETの10倍のスコアなので、更新系の操作を早くしたほうがスコアになりやすい。
でも大体チューニングは参照系を早くする方がノウハウが多いので、ギャンブルとしてはPOSTはエラーにして、
GETだけを超高速にするのもありです。

チューニング条件

  1. DBはMySQLにすること。
  2. アプリケーションを改変することはNG(設定系の変更はあり)
  3. RubyMySQLのバージョンや配布されているモジュールを変更することはあり。
  4. その他、フロントエンドのモジュールを変更することもあり。

基本的にアプリケーションの改変はNGですが、それ以外なら何をやっても良い、という印象でした。
フロントエンドのデフォルトはWebrickだったのですが、これもnginxとかに変更しても良いらしいです。

自分がやったチューニング


前半


とりあえず、全体的な性能が知りたかったので、まずはdstatを入れました。
そうすると、メモリが完全に遊んでいることと、idleするCPUが50%位あることが分かりました。
この段階でScoreは2.0程度。

MySQL側はそこまで時間がかかっていないのですが、下の本を読んで学んだ所から、とりあえずmy.cnfに以下の値を追加しました。

Webエンジニアのための データベース技術[実践]入門 (Software Design plus)

Webエンジニアのための データベース技術[実践]入門 (Software Design plus)

[tuning]
skip-name-resolve
max_connections=500
thread_cache_size=200
table_cache=400
key_buffer_size=256M
query_cache_size=512M
sort_buffer_size=128M
read_buffer_size=128M
read_rnd_buffer_size=128M
tmp_table_size=128M
join_buffer_size=128M
innodb_buffer_pool_size=1024M
innodb_flush_method=O_DIRECT
skip-innodb_doublewrite

これだけでScoreは2.5〜2.7位。

全然なのでMySQL側ではなく、Ruby on Railsの設定をいじってみる。
development.rbの中身を見てみる。でも正直よくわからんので、調べながら調整する。

Tuningathon::Application.configure do
  # Settings specified here will take precedence over those in config/application.rb

  # In the development environment your application's code is reloaded on
  # every request. This slows down response time but is perfect for development
  # since you don't have to restart the web server when you make code changes.
  config.action_controller.perform_caching = true
  config.cache_classes = true

  # Log error messages when you accidentally call methods on nil.
  config.whiny_nils = true

  # Show full error reports and disable caching
  config.consider_all_requests_local       = true
  config.action_controller.perform_caching = true

  # Don't care if the mailer can't send
  config.action_mailer.raise_delivery_errors = false

  # Print deprecation notices to the Rails logger
  config.active_support.deprecation = :log

  # Only use best-standards-support built into browsers
  config.action_dispatch.best_standards_support = :builtin

  # Raise exception on mass assignment protection for Active Record models
  config.active_record.mass_assignment_sanitizer = :strict

  # Log the query plan for queries taking more than this (works
  # with SQLite, MySQL, and PostgreSQL)
  # config.active_record.auto_explain_threshold_in_seconds = 0.5

  # Do not compress assets
  config.assets.compress = false

  # Expands the lines which load the assets
  config.assets.debug = false
  config.action_controller.allow_forgery_protection    = false

end

これだけでScoreは2.5 => 5.5位になった。
この時で1時間半くらい。
Twitter上で6超の声が出始める。

後半


この後色々と調べてruby on railsの設定をいじっていたけど、スコアは平行。
ずっと気になっていたRubyのバージョンが1.8である所に注目して、ここをアップグレードしてみようと思い始める。
Rubyの最新は1.9.3、1.9.3だとGCの設定がいじれるみたいなので、メモリチューニングに役立つと思い、実行。

これはかなり大変だった。ruby 1.9.3を入れただけだともちろん動かないので、gemから依存関係のあるプラグインをインストール。

gemのアレコレがないとか怒られすぎて、この時、知識がないのにRubyのアップグレードなんかやめりゃ良かったとか思ってた。
なんとか16時前に動き始める。

このときスコアがjump up。
5.5 => 11!

まだまだdstatを見るとまだまだメモリが遊んでいるので、GC設定。

色々調べると天下のcookpad様がテスト高速化のために以下の設定を行なっているとのこと。

export RUBY_GC_MALLOC_LIMIT=600000000
export RUBY_HEAP_SLOTS_GROWTH_FACTOR=1
export RUBY_HEAP_MIN_SLOTS=1000000
export RUBY_HEAP_FREE_MIN=2000000
export RUBY_HEAP_SLOTS_INCREMENT=1000000


この設定でやったらもう少し上がって17前後、最終的に
Scoreは17.15で8位でした。
瞬間最高風速では、18まで行きました。

反省点

  • フロントエンドいじらなかった。nginxとかにしようと思ったのにRoR側の設定がよくわからなくて厳しかった。
  • memcached入れたのにRoR側の設定がよくわからなくて結局無駄に。
  • 知らないこと多すぎ。vanishとかunicornとか。

今回8位になったのは完全にたまたまなので、もう少し勉強しようと思います。まずはRubyから。

ちなみに1位と2位はScoreが1000を超えている神のような方々でした。
2位の@netmarkjpさんのブログが早くもアップされているので、参考にしてみてください。
#tuningathon #4に参加しました | netmark.jp


いやー楽しかったー!!また参加しよう。

参考にしたサイト


Rubyでガベレージコレクションの設定をチューニングしてみた - さかなチキンぱん。
MySQLを高速化したいときのチューニング方法
Programma-blog: EC2 + Basic Amazon Linux にRails環境を用意する