2017/10/21〜22 に開催された ISUCON7 の予選に参加して、予選突破できたので、そのときのメモです。 22日(日曜)の方に参加しました。

チーム構成

チーム名

oops

メンバー

  • 2matz(インフラ、アプリ)
  • nyaa(アプリ、インフラ)
  • kjm(インフラ、アプリ)

今は全員同僚

選択言語

Go言語

点数の推移

oops のみのグラフ

16時くらいまでは暫定一位だった。

予選通過チームを含むグラフ

時間 Score
13:05:29 3,468
13:15:12 6,036
13:47:44 17,721
13:53:41 19,535
14:00:59 1,733
14:02:11 27,345
14:18:39 19,320
14:29:11 26,212
14:30:58 82,260
14:32:33 85,310
14:49:54 36,704
14:52:45 27,995
15:18:13 100,117
15:22:43 69,093
15:29:11 31,157
15:38:11 65,097
15:39:40 68,131
15:42:03 106,396
15:48:01 98,140
16:03:03 85,097
16:08:42 142,119
16:18:00 30,340
16:22:39 57,593
16:26:21 44,667
16:30:43 38,876
16:32:31 67,046
16:37:13 37,649
16:42:17 46,491
16:45:52 32,706
17:01:03 91,630
17:04:12 58,803
17:17:53 70,538
17:22:52 30,633
17:25:25 43,560
17:31:02 69,867
17:50:31 162,094
18:00:43 127,168
18:02:54 127,999
18:04:09 109,519
18:12:04 123,991
18:17:29 63,554
18:20:45 48,520
18:23:24 181,188
18:27:27 158,768
18:39:22 163,762
18:45:01 189,698
19:08:04 98,758
19:09:15 70,864
19:12:53 69,786
19:15:39 69,863
19:26:00 208746
19:38:05 215,780
19:56:24 184,449
20:03:47 202,946
20:08:39 175,430
20:13:03 161,017
20:15:08 174,941
20:29:59 146,447
20:31:13 217,747
20:35:43 199,209
20:38:50 183,515
20:40:36 146,219
20:43:27 179,772
20:46:04 185,481
20:49:13 215,451
20:50:39 195,725
20:51:47 167,884
20:53:04 216,923
  • Best 217,747
  • Last 216,923

結果

両日3チームを除いた上位12チームにおいて、8番目(全体で14位)でなんとかギリギリ本戦出場権を得られました。 ISUCON4 以来の2回目です。 ちなみに ISUCON4 のときも総合トップ13枠で8位だった。

使用したツール

  • kataribe
    • matsuu++
  • tcpdump
  • Wireshark
  • goreplay
    • 今回は複数台サーバがあったのであまり使わなかったが、ローカルでリクエストをリプレイしてアプリの挙動に問題ないか確認に使おうと思っていた。
  • netdata
  • NewRelic
    • Go のライブラリだとあまり意味がなかった
    • Runtime GC のところだけチラっと見たくらい
  • BitBucket
  • ansible
  • mosh
  • Dropbox Paper

やったこと

前日まで

  • Dropbox Paper で当日のスケジュールをおおまかに決め共有
  • Pixiv ISUCON で勉強
  • 当日のお昼ご飯
    • 事前に出前を予約。 Launch

当日

序盤

  • 初期セットアップ
    • ソースコードを git にぶっこんでサーバで git pull が行えるようにする
    • ツールのインストールやSSH鍵を登録する Ansible Playbook をサーバに展開、適用
    • fail2ban 無効化
      • 事前に Ubuntu を試したときにハマったメンバーがいたので。
    • 画像のスタティックファイル化
      • nyaa がさくっと実装
      • pixxiv-isucon 予習の成果
  • nginx の設定をチューニング1
    • Expires, Cache-Control ヘッダまわりを追加
    • ETag 無効化
    • これも nyaa がさくっと設定
    • pixxiv-isucon 予習の成果
  • message テーブルにインデックスを張る
    • ALTER TABLE message ADD INDEX(channel_id);
    • これも nyaa
  • /message のチューニング
    • N+1 を改善
    • これも nyaa
  • /fetch のチューニング
    • 私が担当したが N+1 のクエリの排除までいけず。
    • haveread を Redis 化した方が良いよなーとつぶやいてたけど、結局実行せず。
    • nyaa にバトンタッチして改善
    • time.Sleep を消したりもしてみたが、リクエスト数が増えるだけで効果がないので戻した
  • このあたりのベストスコアが142,119点だったけど、なかなか安定せず

中盤

  • message テーブルにさらにインデックスを追加
    • ALTER TABLE message ADD INDEX(user_id);
    • 最終的に ALTER TABLE message ADD INDEX(channel_id, user_id); というインデックスに集約。
  • 複数台構成への変更
    • いくつか案が出た
      • 没案としては NFS や WebDav など。
      • NFS は再起動時に刺さりそうだったのでやめた
    • /icons 以下を3台のサーバに分散配置し、ローカルにない場合は存在するノードにリダイレクトするような処理を2matzが実装
      • 残念ながらベンチマーカーがリダイレクトしてくれなかったのでロールバック
    • nginx のみで複数台構成への切り替え
      • 私が担当した。
      • 上で書いた分散配置の施策は変更が大きくなりそうだったため、予備の案を考えておいた

app1, app2

server {
        location /icons/ {
                proxy_pass http://app3;
        }
        location / {
                proxy_pass http://127.0.0.1:5000;
        }
}

app3

upstream backend {                                                              
        server app1:5000;
        server app2:5000;
}
server {
        location /icons/ {
                add_header Pragma public;
                add_header Cache-Control "public, must-revalidate, proxy-revalidate";
                expires max;
                etag off;
        }
        location /profile {
                proxy_pass http://127.0.0.1:5000;
        }
        location / {
                proxy_pass http://backend;
        }
}

終盤

  • app1, app2 に proxy_cache の設定を追加
  • /history を改善
  • サーバの再起動テスト
    • 1台ずつ再起動し無事起動してくることを祈る
  • 各種ログの停止
  • MySQL のチューニング
    • innodb_doublewrite = 0
    • innodb_flush_log_at_trx_commit = 2
  • ベンチガチャ
    • Goのアプリのメモリが肥大化するので、ベンチのたびに再起動させたり。
    • ベストスコアに近い値を出すまで繰替えしベンチ
  • 祈り

まとめと反省

  • だいたい nyaa の成果。

    • nyaa に感謝
  • 「推測するな計測しろ」の原則をあまり守れなかった

    • netdata を使ってウォッチしていたが、大まかにしか見れていなかった
    • ISUCON の場合 Mackerel などで見れる 1分単位のメトリクスだと粒度が粗いので netdata を入れて見るのが楽。
      • ただ複数台をウォッチしにくい
    • 2015年の記事で使用している PrometheusとGrafanaでダッシュボードを用意したかった
  • 毎度のことながら SQL 力の不足

  • 毎度のことながら コミュニケーション不足

    • 前回より大分マシだった
    • 座席の位置とかも重要かもしれない
  • app3 に負荷が集中する構成だったのは良くなかった

    • app1, app2 だけでベンチを走らせてみればよかった
  • ベンチマーカーのエラー「too many connections」の発生条件がよくわからなかった

    • 同時接続数の問題なんだろうけれど、ベンチマーカのバグなのか、仕様なのか判断がつかなかった。

    10/22 18:27:20 エラーが発生したため負荷レベルを上げられませんでした。2017-10-22 18:27:19.812958767 +0900 JST m=+56.143739094 リクエストに失敗しました Post http://isubata.example.com/message: dial tcp 59.106.218.178:80: socket: too many open files (POST /message )

  • ルールを熟読しよう

    • どのようなリクエストのポイントが高いのか、ルールに書かれているのならば把握して意識すべき

最後に

pixiv-isucon を作成、公開してくださった catatsuyさん、毎回大変な準備をされている運営の皆様には深く御礼申し上げます。 本戦がんばろう。