大森s ISUCON5 初参加6位でした

毎年TLから見学していたISUCON、今年は社内メンバーの勧誘に成功したので初参加しました。
メンバーは みね, @yukiex, @shun0922 の3名で参加してきました。チーム名は会社の所在地ということで 大森s に。

本戦も予選も役割分担はだいたい以下のような感じで、お互いの領域を少しずつカバーしながら作業しました。

  • みね ・・・ App
  • @yukiex ・・・ インフラ
  • @shun0922 ・・・ DB, KVS

当日の朝

今は横浜ですが、東京在住の頃から渋谷は怖くてあまり近づかなかったので迷うかと思って早めに出発。
9時頃には11Fに到着し、先に到着していたのは2組程度でした。
個室ゲットできるといいなと思っていたら、メンバーが乗車している電車で人身事故が発生したと連絡。
到着が遅れチーム全員揃わないと入れないバリアに阻まれ立ち往生。それでも10時前には入場できました。

普段 MBA 11' に外部モニタという構成なので、モニタのかわりに MBA 13' を追加で用意したり、メンバーのために燃料(カフェオレ)を用意したりと、バッグがいい感じの重量(20kg程度)になってました。

開始直後

配布された封筒からホストとIPがわかった時点で開発機などに hosts ファイルを配置しメンバーに共有。
開始と同時にキューを入れ、それが記念すべきISUCON5Fの初キューだったらしくスコア1064で1位!

レポジトリにソースを取り込み App をのぞきはじめたメンバーからAirbnbを3行で説明しろと言われたので、

一般人が
一般人を
泊めるサービス

と説明。「えっ?ホームステイ的な!?」となっていたので「空き部屋に」を補足。

こちらではまず OS が Ubuntu 14.04.3 なことを確認。
Chef のレシピが適切なものを準備出来ていないため iTerm2 の Broadcast Input と、pssh を駆使して3サーバの環境を同時に修正。
hosts, shell, key 修正 (isucon, root ユーザ)、dstat, htop, zsh などを入れる。
ミドルウェア周りはDBサーバが psql (PostgreSQL) 9.4.5 で nginx が 1.4 なことを確認。この辺で15分経過。

メンバー2名はここ数ヶ月 PostgreSQL と過ごしてきたので小さくガッツポーズする。
App 担当は PostgreSQL の経験がほとんどなく、さらに開発環境が Mac じゃない上に VM 環境もないということで手元に開発環境が構築できないため、VPN越しに社内に環境を作る。しかし直接API接続できないということで諦めて c サーバに居を移す。

vim の設定やら ag もいれつつ、スーパーバイザーを探して perl に変更、自動起動などを変更する。
そして nginx に worker 数、静的コンテンツ配信と UNIX domain socket の設定、supervisor 側に Gazelle の設定など、同時に変更するもなぜか nginx の configtest で fail する。
なんとか設定変更を最小限にとどめ、とりあえず nginx start する。

午後

となりでDB担当が pgBadger を使って slow query をまとめてくれたので眺めてみるも、あまり最適化の余地がない。この辺で12時15分頃。

App 側で JSON モジュールを JSON::XS に変更。
アクセスログalp で集計して眺めながら 外部API 呼び出しをなんとかしないと、他にはあまり余地が無いという話になる。
気休め程度に endpoints をコードにインプリメントする。スコア2781。

13時30分頃、Redis でキャッシュする方針で、サーバインストールと設定、Perl設定、App実装とそれぞれが実施。
ついでに前回調査時に Furl より Net::Curl のほうがベンチ結果が良かったということで Net::Curl も cpanfile に仕込む。
Redis の実装が完成する前に API とのやり取りを確認したかったということもあり Varnish をプロクシとしていれるように作業。エンドポイントをバックエンドにマッピングしてひとまず動作する。

13時45分頃、DBにインデックス create index users_email on users (email, passhash) を追加し少しスコアあがる。
Net::Curl で Last-Modified 対応と、Accept-Encoding 模索するが、Redis 待ちで一旦放置する。
14時30分頃、Redisの実装が完了、5000〜6000程度までスコアが上がる。

後半残り3時間

そして運命の15時15分から数分前、再度 nginx の設定を変更していてやっぱりおかしい。作ったはずのソケットがない。
あ、俺 supervisorctl reload するの忘れてるやん!!と自分の凡ミスにいまさら気づく
15時15分頃、やっとワーカーが増え Gazelle と UNIX domain socket の導入ができたのでベンチする。スコア 30807 。ワーカー数を倍にして 61552 、更に調整して 65295 に落ち着く
その間、App 側は着々とキャッシュの実装を追加し Expire の個別対応、token_key の設定などを実施。

15時45分頃、そろそろ複数サーバで負荷分散できるようにしたいということで、2台で調整を開始。
/initialize の初期化対象DBホストがローカルだったのを見落としていて少しハマる。
redis の bind など変更してテスト、Varnishも外す。
DB担当は pgpool-II を入れるかどうかでやきもきしていたようです。

2台の構成

isu08a DB, App  
isu08b LB, Redis, App  

isu08b (nginx) -> (App)  
               -> (nginx) -> (App)  

上記のように nginx to nginx の若干、変則的な設定を実施。
16時30分ごろ、スコアは 69880 となり3位になったので reboot テストなどを実施する。

残り1時間

17時10分頃、userjs のレンダリングをやめて直接生成に変更。スコアを 83776 まで上げ3位を維持。

たまに fail するので Tenki API のキャッシュ保持をいつまでするかを調整開始
また reboot 直後に fail することがあり、PostgreSQL で App が DB 接続した後に DB が落ちると接続がロストすることを思い出す。念のため env.sh に sleep を仕込む。

17時30分頃、サーバを3台体制に変更しベンチを実施。スコア 90120 とチームとしては今大会の最高スコアを記録。

17時40分頃、fail 対策で Tenki APIのレスポンス日時からキャッシュ時間を調整するように変更。
全サーバ reboot テスト。スコア 84983 にダウン。

17時50分頃、更にTenki APIのキャッシュタイムを5分から60秒に変更。

結果

17時56分の段階で best score で5位、上位陣の fail などでなんとか入賞に望みをかけましたが結果6位でした。
後になってみると、ツメが甘い上に対応も甘く反省しかない結果でした。
なにより上位陣がしっかり着手していた、並列リクエストができていなかった点は痛かった。
データのシリアライズに関しても MessagePack やもっと効率のいい方法を使うべきだったし。
gzip_static などもヘッダをしっかり読み、基本に忠実であればできたはずでした。
非常に悔いが残りましたが、自分たち(主に自分の)未熟さがそのままスコアに反映された結果なため満足です。

来年までにクソ精進する。

最後に、941 さん、tagomoris さん、kamipo さんをはじめ運営・出題チーム、スポンサーの皆様、本当にありがとうございました。
非常に楽しかったです。

Score History

timestamp score note
11:01:58 1064
11:50:04 1029
12:01:42 0 FAIL:
12:27:59 0 FAIL:
12:35:06 0 FAIL:
12:55:24 968
13:10:44 1012
13:12:53 0 FAIL:
13:16:39 1023
13:34:03 985
13:37:21 0 FAIL:
13:40:42 1094
13:51:48 2781
13:52:37 84 FAIL:
13:56:43 84 FAIL:
13:59:35 1026
14:09:01 2023
14:09:37 84 FAIL:
14:12:26 1899
14:14:59 2658
14:27:46 5268
14:29:13 6298
14:30:44 5759
14:32:21 1173
14:34:25 971
14:41:46 1176
14:44:34 1097
14:51:12 1051
14:52:53 5481
14:57:12 1088
15:02:02 84 FAIL:
15:06:50 6438
15:08:29 84 FAIL:
15:10:17 1013
15:13:04 5624
15:15:12 30807
15:20:01 0 FAIL:
15:21:30 61552
15:24:52 58009
15:26:30 0 FAIL:
15:28:09 65295
15:30:35 58569
15:32:27 0 FAIL:
15:33:50 0 FAIL:
15:34:16 40 FAIL:
15:38:37 57888 FAIL:
15:40:19 71 FAIL:
15:42:53 71 FAIL:
15:45:29 55325
15:57:46 59 FAIL:
15:58:29 59 FAIL:
16:01:23 84 FAIL:
16:02:15 84 FAIL:
16:03:43 53708
16:08:34 84 FAIL:
16:11:24 84 FAIL:
16:13:41 84 FAIL:
16:17:36 84 FAIL:
16:22:53 73 FAIL:
16:24:52 69880
16:25:27 84 FAIL:
16:28:13 0 FAIL:
16:33:58 67431 FAIL:
16:36:00 84 FAIL:
16:38:10 84 FAIL:
16:40:25 63105
16:41:10 84 FAIL:
16:43:49 52687
16:45:34 10450
16:49:10 84 FAIL:
16:51:59 54244
16:54:39 57995
16:56:35 84 FAIL:
17:00:07 40 FAIL:
17:01:41 55920
17:09:08 83776
17:13:31 0 FAIL:
17:15:18 0 FAIL:
17:17:22 0 FAIL:
17:19:33 79152
17:21:39 0 FAIL:
17:24:33 78635 FAIL:
17:27:23 71501
17:29:49 90120
17:33:53 49139
17:39:38 84983
17:42:55 81641 FAIL:
17:46:59 40026
17:51:30 74185
17:56:31 84114