tuningathon 4 に参加&優勝してきました

というわけで3回目のJavaではボロボロでしたが、 @ijin さんと再び tuningathon に参加して、優勝してきました。

ルール

レギュレーション があるのでそれを参照。refineryていうRoR製CMSのブログ機能のチューニングがお題でした。

やったことを時系列順で

※スコアの移り変わりや、このエントリで触れていない点については相方@ijinさんのエントリが詳しいので、合わせてご参照ください。

  1. rbenv + ruby-build で Ruby 1.9.3-p194 を入れる
  2. Railsのアプリサーバにunicornを使う
  3. MySQLにいくつかindex追加
  4. 計測ツールを眺めてスコア算出方法を調査
  5. Varnishでキャッシュをかます

rbenv + ruby-build で Ruby 1.9.3-p194 を入れる

rvmもあるんですが、rbenv + ruby-build のが扱い易いので良いかと思います。インストール方法は巷にいっぱいあるので割愛。今回スタート時のRubyが1.8.6?とかだったけど、1.9.3にしても普通に動きました。

JRubyも試そうかという話もあったのですが、Gemfileをいじってはいけないという制約があり、mysqlのコネクタ変更出来ないのでこちらは断念しております。

Railsのアプリサーバにunicornを使う

これも通常の運用だとGemfileに追記してbundleしたいところなのですが、前述の制約がありますので、gem install unicorn-rails して rbenv の system にインストールするところだけ少し注意という感じです。

インストール後、多分ポイントになる設定は以下の二つ。

  • unicornのworker数
    • 2コアサーバだったのでworker数も2に。4にしたらパフォーマンス下がった
    • でもここの適正値っていうのはちゃんとまだ分かってない…
  • GCをoffにする
    • こんなコードを入れてGCをoffに。ただしずっと動かしっぱなしにするとメモリをモリモリするので適度にunicornの再起動が必要になります
after_fork do |server, worker|
  GC.disable

ちなみに設定ファイルは弊社で運営しているSqaleのサーバのファイルを参考に時間短縮 (宣伝です)

MySQLにいくつかindex追加

Railsのdevelopment.logを見ながら遅そうなクエリ解消の為にindex追加を行いましたが、大体が1ms前後のものばかりだったので、ここらへんは正直やらなくてもよかったなと。

計測ツールを眺めてスコア算出方法を調査

レギュレーションには説明が書いてあったものの、やっぱり中身を見てみないと分からないだろうということで、スコアの算出方法を調査しました(計測ごとに振れ幅がデカくてどこを直せばいいかの指針が欲しかった)

レギュレーションも踏まえてポイントをまとめると

  1. GETのレスポンスを測るhttpd_loadが走ってる
  2. それとは別にPOSTとGETを交互で且つ反映チェックを行うアクセスがくる
  3. POSTのあとのGETの反映チェックがしくじると著しくスコアダウン

というのはコードベースでも分かってきました。2のGETとPOSTが交互ということは、後述するVarnishのキャッシュが有効に働かないのではないかとう懸念はあったのですが、1のアクセスはそれよりも高い頻度でバンバンくるんでいけるかもというのもここら辺で分かった感じ。

且つ大体このちょっと前辺りで @netmarkjp さんがスコア1000以上とかを叩き出してたので、@ijin さんと二人で 「Varnish使ったな & 効くんだな」と話してました。

Varnishでキャッシュをかます

この時点である程度のチューニングは思いつくところが終わった感じです。スコアはこんな感じ。

計測ツールの内容から

  1. GETは早く返してスコアを稼ぎたい
  2. POST後の反映チェックはなるべくしくじらないようにしたい

となり

  1. VarnishでRailsからのコンテンツをキャッシュしてGETのパフォーマンスをあげつつ
  2. POSTがあった場合はキャッシュを破棄して反映チェックを通して減点されないように

するのが良さげということになりました。

計測時

この時点ではまだVarnishのキャッシュ設定が固まってなかったので、 tuningathon運営側の公式計測が来る前に

  1. データベースのデータ初期化
  2. unicornの再起動

を都度行い、Ruby+アプリサーバチューニングの状態で2回計測してもらってまず実績を作りました。

その後、@ijin さんが @netmarkjp さんのブログにあるようなbanの設定を入れて、そこからさらに運営側の計測が2回きたと思うのですが、なんとかその間にハイスコアを出せたようです。

所感とかまとめとか

やった内容で設定とかコードベースの記載が少ないのはちょいちょい追記していければと思います。

今回は計測スタート時からCPUバウンドだったので、チューニングの指針としては

  1. CPUを使う処理の効率をどうあげるか (Rubyとかアプリサーバ周りのチューニング)
  2. そもそもRoRに仕事をさせないようにするにはどうするか (キャッシュ周りのチューニング)

の2つがあったかと思います。1の方は序盤に頑張れましたが、2でいきなりジャンプアップして皆の戦意を喪失させた @netmarkjp さんは流石だなあとw チューニング時間が2時間とかだったら余裕で負けてた。

ただ、環境周りの地道な取り組みも効果は出る(というかそこが勝負を分けたところ)とも思うのでその辺りのバランス含めても面白い企画だったと思います。

もう少し頑張れたかなと思うところ

  • unicornのkeep-alive周りとか
    • 最後らへんでコネクションが詰まり気味になってるところがあったのでそこ直せたらまた数値違ったのかも

その他

懇親会ではお互いやったこととか、それ以外の仕事の話や悩み相談など沢山あって大変良かったです。あと見た目がチャラいと色んな人に言われて俺はいたく傷つきました。

次はまたどういう形になるか未定とのことですが、また機会あればチャレンジしてみたいと思います。

あ、そうだ! ペパボではインフラエンジニア始め色々な業種で採用の募集をしております!! (※参考)

一位、二位陣営。おめでとう!! #tunigathon on Twitpic
最後に @fujisaki_hb さんがアップされてた写真を拝借

運営の皆様、ありがとうございました & 参加された皆様、お疲れさまでした。

技術評論社さん、ゼロスタートさんの記事も楽しみー。