ISUCON9の予選をRubyで通過しました

Posted by Yutaka Hara on September 11, 2019 · 1 min read

NaCl 松江本社のyharaです。こんにちは。Webアプリケーションの高速化技術を競うコンテスト「ISUCON」に弊社メンバーで参加し、予選を突破して本戦に出場できることが決定したので、簡単ですが参加記を書こうと思います。

15位のチーム「yarunee」が我々です。最終スコアは11,160 イスコインでした。この記事によると予選突破チームのほとんどはGo言語を使用していたようですが、弊チームは一番使い慣れている言語ということでRubyで参加しました。

ISUCONとは

ISUCONは2011年から行われているコンテストで、課題となるアプリケーションが与えられ、それを(挙動を大きく変えない範囲で)最も性能が出るよう改造できたチームが優勝、というイベントです。

今回はAlibaba Cloudのクーポンが参加者に付与されて、そこにインスタンスを立てて作業するという流れでした。対象となるアプリは本番の朝にイメージファイルという形で提供されました。

スコア遷移

スコアの遷移は以下です。ラスト30分で大きく上がっていることが分かります。

これは何をしたかというと、MySQLとアプリケーションを別ホストにしたのでした。今回はインスタンスを3台まで使ってよいルールだったので、topコマンドで一番CPU負荷が高そうだったMySQLを別ホストに切り出しました。

極めて普通の作業ですが、コンテストという状況から残り時間を見て焦ったり、あるいは別の高速化施策とバッティングしたりすると、簡単には行かなかったかもしれません。実際に必要だった作業は以下です。

  • アプリケーションのDB設定を変更
    • web.rbを見ると、ENV(環境変数)からDB設定を取得していることがわかる
    • systemdのisucari.rubyの設定を見るとenv.shというファイルを読み込んでいるので、このファイルを書き換える
  • DB初期化スクリプトの設定を変更
    • web.rbの/initializeが、init.shというスクリプトを外部コマンドとして実行している
    • init.shのMySQLのホストを書き換える
  • MySQLの設定を変更
    • bind-address 127.0.0.1だとローカルからしか接続できないので

pumaの設定

そこからもう少し上がっているのは、pumaを複数プロセスに変更した結果です。systemdの設定ファイルで rackup -p 8000 となっているところをpumaコマンドに変え、puma -p 8000 -w 4 のようにすることで、ワーカー数を増やすことができます。個数については2→4→5と試して、一番良かった4を採用しました(3は時間の都合で試せませんでした)。

Sinatraをproductionにする

他にやったこととして、Sinatraをdevelopmentからproductionモードに変更したというのがあります。前述のpumaコマンドの場合、puma -p 8000 -e productionのように-eで設定できます。

環境構築について

10時〜18時という長丁場を快適に戦うためには、サーバ上の環境を快適に整えることも大事です。今回はあまり準備はしていなかったのですが、とりあえず.vimrcに以下を追加したのと、

autocmd FileType netrw nnoremap <buffer> <silent> h -
autocmd FileType netrw nnoremap <buffer> <silent> l <CR>

screenを入れて以下のような.screenrcを作成しました。LoadAVGが出せることはこちらの記事で知ったのですが、たまに便利だったりしました。

escape ^Zt
hardstatus alwayslastline "%{= cd} %-w%{= wk} %n %t* %{-}%+w %= LoadAVG [%l] "

できなかったこと

インスタンスが3台あるのでSinatraアプリを3台に配置してロードバランスさせたかったのですが、エラーが出て断念しました。

1つ目のエラーは商品画像がダウンロードできないというもので、これについては画像を1台に寄せる(ロードバランサであるnginxの設定で、/sell/uploadはかならずホスト1に飛ぶようにする)ことで解決しました。

一方2つ目のエラーは/new_item/xx.json の商品数が正しくありません というもので、こちらは未解決です。当該のjsonを返す処理自体は特に分割で壊れるようには見えなかったので、CREATEが壊れているのではという話は出ましたが、どうだったんでしょうか。

その他の施策

アプリケーションコードをいじる系の修正は前田さんがやってくれたので、結果的には僕のコードはほとんど入っていないです。

しいていえばロガーの設定が僕ですね。requireを冒頭以外に書くのはあまり普通ではないですが、今回は元からあるコードと区別しやすい方が良いかなということでこうしています。ロガーはここで使っています(コミットし忘れていますが、実際には$!nilである場合のチェックが必要です)。

本戦について

予選を突破したということで、10/5(土)の本戦に出場する予定です。メンバー3人とも島根県在住なので、宿と飛行機を取らないとなと話しています。当日はよろしくお願いします。