ISUCON7の予選で敗退した

Blogにまとめるまでが、ISUCON

と、言うことで久しぶりにこっちに書く。

前から興味はあったけれど、参加者のブログを見る程度だった。

そんな時に、会社の同期に誘ってもらったので、ホイホイ受けてみた。

事前準備

過去問がVagrantで公開されているので、本番と同じ10:00-18:00でISUCON6の問題を解いてみる、ISUCON5の問題をざっくり読んで改善点を挙げる、というゆるふわな対策を行った。GitHub Privateにリポジトリを用意したり、Google DocにTODOリストを作成したりと、ここまでは良い感じだった。

github.com

自分の担当はDeploymentだったので、AnsibleのPlaybookをちょこちょこ作っていた。最近は専らDockerfileを書いているので、すっかり使い方を忘れていたけれど、Best Practices — Ansible Documentation 見ながらなんとなく書けるので、Ansible楽で良い。

Host Machine -> Vagrantで立ち上げたisucon5用のVM にansible-playbookするためのinventory fileはこんな感じ。

当日

開始直後

いきなりインスタンスが3台あってちょっと焦る。

とりあえず、Ansible script流す。InventoryにIP Address追加するだけだから、流す分には特に困らなかった。なお、各自のssh keyは ssh-copy-id で送れというスパルタ仕様。

そして、ベンチ走らせてみる、確かデフォルトがPythonで1台にだけ負荷をかけた状態。

Time    2017-10-22 13:27:06 +0900 JST
Message ok
Score   2282
Best    2282
LoadLevel       1

Goに切り替える。やっぱり1台だけ。

Time    2017-10-22 13:32:00 +0900 JST
Message ok
Score   4521
Best    4521
LoadLevel       1

2台だと?

Time    2017-10-22 13:35:38 +0900 JST
Message ok
Score   5030
Best    5030
LoadLevel       1

あんまり増えないね。

ということで、コードリーディングタイム。

14過ぎ辺り

改善できそうな所を出し合う。

alp用のログフォーマットをNginxに適応して、実際のデータを確認。これは、最初にやっても良かったかも。あと、access_log /var/log/nginx/access.log ltsv;パスの後ろにltsvをつけ忘れるという凡ミスを犯した、ごめん。

github.com

DBのチューニングや、index効いてない、N+1問題などベタな所を修正。

iconの画像を、毎回DBから取得しているのが遅いよね。ということで、静的ファイルに書き出してNginxから返そうという方針に。

16時過ぎ辺り

新規、更新のiconはファイルに吐けるようになったので、既存の画像もファイルにしてしまおう。

Time    2017-10-22 16:43:26 +0900 JST
Message 負荷走行前のバリデーションに失敗しました。2017-10-22 16:43:25.201090568 +0900 JST m=+1.524851228 [Fatal]画像データが正しくありません (GET /icons/65ea5a70b1fcf8f5f816b01b87f2aca2251315b0.png )
Score   0
Best    7225
LoadLevel       0

謎のバリデーションエラーにより、Nginxから返す作戦を諦めアプリから返すように戻す。

しかし依然として出続けるバリデーションエラー。。。

この時は、変更を1号機にしか適応していなかったので、2号機に1号機のバイナリを持って行って再現確認。結果、再現せず。

ベンチマークツールに変なファイルキャッシュされたのか?と散々悩む。

18時過ぎ

ダメだ、バリデーションエラーが出続ける。もう、諦めてラーメンか?という思いの中、DBのデータから静的ファイルを生成するロジックを書き換えたら、バリデーションに通った!危うく、ISUCONに出たこと自体を無かったことにするとこだった。

Time    2017-10-22 18:21:50 +0900 JST
Message ok
Score   23513
Best    23513
LoadLevel       1

その後、iconはinitializeの時にNginxのメモリに載せたいよね。という話になるが

で、どう設定すれば良いの?

という残念な状態になり、必死にググるおっさんたち。

20時過ぎ

せめて、アプリを3台にスケールしようということで、2号機とDB用だった3号機にもアプリを展開。

Nginxのログを切って、MySQLのSlow Queryログも切って、できる限りのことをした結果。

Time  2017-10-22 20:50:48 +0900 JST
Message  ok
Score  42731
Best  44732
LoadLevel  1

4万ちょいでフィニッシュでした。

総評

Ansibleでスマートにデプロイしたかったけれど、makeが通らない!等焦ってしまい、書き捨てのShellで凌いだのが負けた気分だったし、そもそもデプロイするところまで事前に用意しておくべきだった。

ETC_BR=${1:-master}
APP_BR=${2:-master}

cd /etc.git
sudo git fetch
echo "[INFO] Checkout $ETC_BR"
sudo git checkout $ETC_BR
sudo git pull
sudo cp -r /etc.git/nginx/* /etc/nginx
echo "[INFO] Restart Nginx"
sudo systemctl restart nginx

cd /home/isucon/isubata/webapp/go
git fetch
echo "[INFO] Checkout $APP_BR"
git checkout $APP_BR
git pull
make
echo "[INFO] Restart Go APP"
sudo systemctl restart isubata.golang.service

あと、過去何度もNginxが登場しているというのに、Nginxへの理解が低すぎたのは大変よろしくなかった。

とても悔しかったので、来年リベンジしたいな。