Speee DEVELOPER BLOG

Speee開発陣による技術情報発信ブログです。 メディア開発・運用、スマートフォンアプリ開発、Webマーケティング、アドテクなどで培った技術ノウハウを発信していきます!

復習するまでがISUCONです

ヒップホップにハマって要所要所で韻を踏もうとするがあまり、言いたいことも言えないようになった
エンジニアの @mnc です。

いよいよ明日、ISUCON7本戦が開催されます。
今からドキドキがとまりませんが、よく考えたら予選で惨敗していたので明日は何もすることがありませんでした。
「遠足は帰るまでが遠足だ」とはよくいったもので、ISUCONも復習するまでがISUCONだと自分を戒めISUCON予選の復習を行いましたので、そのことについてレポートいたします。

@gfxさんに上位陣の戦略について講義をしていただきました

詳しくは以下のBit Journey社の記事をご参照ください。

blog.bitjourney.com

講義ではISUCON上位陣の戦略の違いを説明していただきました。
3台のサーバーの使い方はそれぞれ異なっていましたが、帯域問題をクリアするために3台全てでリクエストを受け付けているという点では共通していました。 僕のチームは帯域問題を全くクリアできなかったため、上位陣の帯域問題をクリアするための戦略は非常に勉強になりました。

また、

N+1問題は秒速で解決できるくらいになっておかないといけない

という趣旨のアドバイスがあり、 ActiveRecordのincludesメソッドやjoinsメソッドでN+1を解決するということしかしてこなかった結果、SQLでN+1を解決するのに多くの時間を浪費した僕にとっては非常に耳が痛くためになるお話でした。

@gfxさんの講義の様子

f:id:manchose:20171124111900j:plainf:id:manchose:20171124111955j:plain

時間無制限でISUCON7予選の問題を再度1人で解いてみた

勉強しただけでは本番でいきなり成果を出すことは難しいので、
@gfxさんに教えていただいた内容を血肉とすべく1人でもくもくとチューニングしました。
環境はMacBook Pro (Retina, 15-inch, Mid 2015) のmacOS上にVirtualBoxで以下の2台のサーバーを立ち上げて行いました。
matsuu/vagrant-isucon のVagrantFileを使用させていただいております。)

  • Benchサーバー(ubuntu/メモリ2GB/CPU1コア) × 1
  • Applicationサーバー(ubuntu/メモリ2GB/CPU1コア) × 1

WebDAVを使ってpublicディレクトリに画像をアップロードする

今回の復習ではサーバーが1台なのでWebDAVを使う必要はなかったのですが、過去のISUCONでも使う機会があったそうなので勉強を兼ねて導入してみました。
WebDAVとはHTTP1.1を拡張したプロトコルでサーバー上のファイル操作を行う技術です。
Rubyレイヤーでファイルアップロードを実装するよりも短時間で実装できる場合があるため、このやり方に慣れておくと今後のISUCONで役に立つかもしれません。
nginx.confを以下のように設定しWebDAVで画像のアップロードができるようにしました。

dav_methods PUT; # 許可するメソッド
create_full_put_path on; # 必要な全ての中間ディレクトリの作成を許可する。
dav_access group:rw all:r; # WebDAV経由で作成したファイル/ディレクトリのパーミッション設定
# アクセス制限
limit_except PUT DELETE MKCOL MOVE {
    allow   172.28.128.4;
    deny    all;
}

この実装とnginx.confのキャッシュまわりの設定によって GET /icons のパフォーマンス問題はクリアできました。

N+1を解消する①

GET /icons を倒すことができたら次に立ちはだかるのは GET /fetch です。
未読数をチャンネルごとに計算している処理がN+1問題を引き起こしています。
スギャブロエックスチームの実装を参考に、既に読んだ数を別テーブルに格納しておくように変更しました。 GET /fetch ではそれを参照することでN+1問題を解決することができました。 このようなN+1問題の解決方法もさらっと実装できるようになる必要があるので、精進あるのみです。

N+1を解消する②

GET /message でも同様にN+1問題を引き起こしていたのでこちらも対応しました。
こちらは①とは異なりSQLのJoinを用いて解消しました。
ActiveRecordを用いずMysql2を用いて解決することに手間取ってしまったので、このあたりを深く考えずに実装できてしまうくらい鍛錬を積もうと思います。

結果

スコア

初期スコア 最終スコア
11425 37583

これくらいまでチューニングしたところで点数は30000点を超えました。
本番の環境とスペック等が異なっていますが、上位陣が行ったチューニングを実際に手で動かして再現することで血肉となった気がします。
やはり頭でわかっているのと、実際に手を動かして効果がでるまで実装できるのとでは大きな違いがあると実感しました。
なにより バグなく実装する というあたりまえのことができていないことが多く、その修正に多くの時間を使ってしまっていることがわかりました。
この 実装力 を身につけることが今後の課題です。

ISUCON予選の実装内容を公開してくださっている上位チームのリポジトリやブログを参考にして再度実装しなおすことで確かな力になりましたので皆さんもぜひ再実装してみてはいかがでしょうか。
引き続きチューニングを進めて次回大会では本戦出場できるように精進していきたいと思います。

※実装はmnc/isucon7-reviewにあります。