Closed17

ISUCON13参戦記録

vintersnowvintersnow

ISUCON13に参加したので、その記録を纏めておく。

参加経緯:友人に誘われたため
面子の経験

  • 自分:普段はモバイルアプリを作ったり、Pythonのコードを書いたりしている。ISUCONは3回程度参加した経験がある。Goはisuconでしか使わない。
  • 友人:ISUCONは1~2回参加している。
  • 友人の友人:ISUCON初参戦
vintersnowvintersnow

事前練習編

本戦の1週間前に全員で集って、当日スムーズに出来るように準備をした。それまでノータッチだった。

やったこと

  • (友人宅でやったので)、インターネットと作業場所の確保
  • Githubレポジトリの作成
  • デプロイスクリプト
  • ssh鍵を共有しておく
  • Goの開発環境構築
  • etckeeperの導入方法確認
  • ALPの導入方法確認
  • netdata導入方法確認
  • MySQLのslow queryとpt-query-digestの導入方法確認

他の参加者の記録を確認。これが結構やってよかった。どのようなことをするべきか参考になるし、知らなかったツールなどを知れた。

vintersnowvintersnow

今回、New Relicの無料枠をいただいたので、その導入もやってみたが、使いこなせる自信がなかったので本番では使うのをやめた。
ちゃんと導入をすればとても役に立つのは分かる。
しかし、そこまでやるのが大変そうなのと、isuconの場合改善とベンチを繰り返すので、一々過去データを除外するのが大変そうだった。

vintersnowvintersnow

デプロイスクリプトは以下のようなMakefileを作成した。
(競技中にも必要に応じて弄っていた)

REVISION=$(shell date +%Y%m%d%H%M%S)
SERVICE=isupipe-go.service
HOST1=isucon1
SSH_CMD=ssh isucon@$(HOST1)

LINUX_TARGET_ENV=GOOS=linux GOARCH=amd64
BUILD=go build
DESTDIR=.

build:
	cd go && CGO_ENABLED=0 $(LINUX_TARGET_ENV)  $(BUILD) -o $(DESTDIR)/isupipe -ldflags "-s -w"

rotate_log:
	$(SSH_CMD) sudo mv /var/log/nginx/access.log /var/log/nginx/access.log.$(REVISION)
	$(SSH_CMD) sudo mv /tmp/slow.log /tmp/slow.log.$(REVISION)
	$(SSH_CMD) sudo nginx -s reopen
	$(SSH_CMD) sudo mysqladmin flush-logs

deliver: build
	$(SSH_CMD) sudo systemctl stop $(SERVICE)
	scp -P 22 go/isupipe isucon@$(HOST1):/home/isucon/webapp/go
	$(SSH_CMD) sudo systemctl start $(SERVICE)
	$(SSH_CMD) sudo systemctl enable $(SERVICE)

slow_query:
	$(SSH_CMD2) sudo pt-query-digest /tmp/slow.log | tee slow_query_$(REVISION).txt

deploy: build deliver rotate_log
vintersnowvintersnow

本番

最初の放送で概要を知り、動画配信の最適化は難しそうだなと思っていたが、全然関係なかった。
DNSのチューニングも分からんので、結局なんも分からんのは変わらないが。
ちなみに問題名にfinalとついていて、始めて今回予選がないことを知った。

手分けをして以下のことをする。

  • デプロイスクリプトを作る
  • マニュアルを読む
  • netdataを入れる
  • alpを入れる
  • mysqlだったので、slow queryを入れる

これで11時過ぎになっていた。
ベンチを走らせたら、3300ぐらいだった。
netdataは以下の感じ。legendがないが、黄色がmysqlのcpu使用率
DBがボトルネックになっていそうだなと分かった。

vintersnowvintersnow

index貼り

(自分がしたわけではないが)
DBを確認をすると、全然indexが貼られていないので、slow queryなどを見ながら適当にindexを貼っていった。

  • livestream_tagsに livestream_id indexを張る
  • livecomments に、(livestream_id, created_at DESC) index
    を貼ったら、4000ぐらいになったらしい。
vintersnowvintersnow

Icon画像データをDBから剥す

alpを見ると、iconのエンドポイントがリクエスト数も時間も掛っていた。
実装を確認すると、icon画像がDBに直接入っていたので、DBから剥すようにした。

iconは初期データには含まれず、postされて始めてDBに保存される
なので、

  • POSTされたらディスクに書き出しておいて
    • 他のところで、ハッシュ値が必要だったので、それだけ別テーブルで保存しておいた。
  • GETはnginxでサーブするようにした

302を返す処理は一旦無視した。

これで、7000ぐらいになった。

vintersnowvintersnow

DNSのTTLを設定

DNSはどうボトルネックになっているのか分からなかったが、とりあえずTTLはすぐに設定出来そうだからやってみたけど、効果はなかった。

vintersnowvintersnow

2台構成に変更

DBが重そうだったので、mysqlを別サーバに移動することに
デフォルトのアカウントがlocalhostだけだったり、環境変数で接続先が上書きされたり、icon剥しで作成したテーブルをもう一方で作成するのを忘れていたりで、結構沼った。

特に最初の問題は気がつかなくて、分離したけど、全然速くならないなとか言っていた。

無事分離した後負荷を見ると、まだDBのCPUが貼りついていた。

vintersnowvintersnow

livestreamStaticsのN+1の解消

Statics系が結構時間かかっていて重そうだったので実装をみたら、ランキングの集計がN+1になっていたので解消をした。
とりあえず、単一クエリで解消するようにした。(最終的それでも遅かったので、どうしたら良いのだろうか?)
9000ぐらいになった。

この時点で16時過ぎになっていた。

vintersnowvintersnow

3台構成に変更

PowerDNSもmysqlを使用していて、それもCPUを1コア使用していたので、3台目をPowerDNS用DBにすることにした。
PowerDNSごと分離しても良かったが、少しめんどくさ時間がかかりそうだったので、DBの接続先だけ変更をした。

10000点付近をうろついていて、あまり変化はなかった?
が、app serverのcpu使用率に余裕が出来た。

vintersnowvintersnow

userStaticsのN+1を解消

友人が手間取っていたので、N+1の解消を手伝った。

これで、15000点ぐらいなった。

vintersnowvintersnow

themesのuser_idにindexを貼った

大きなN+1が解消したのと、DNSのクエリログが分離されたため、slow queryの結果が変化した。

20000点ぐらいになった。
最後になって改善の速度が上ってきた。

vintersnowvintersnow

DNS DBのrecordsのnameにindexを貼る

なぜか貼られていなかったで貼っておく。
22000ぐらいになった。

vintersnowvintersnow

reservation_slotsの検索を、N+1ではなく空きslotがあるかどうかで判定するように

上記の通りだが、無駄ぽい処理があったので、直した

vintersnowvintersnow

後片付け

各種ログやNetdataを停止した。17:55ぐらいでギリギリになってしまった。

最終スコアは24000ぐらいだった。

vintersnowvintersnow

感想

今回の問題の核心だろうDNSのチューニングに辿りつかなかったのはくやしいが、基本的な最適化でそこそこ速くなったので、大会自体は楽しめた。(今回、alpとslow queryとnetdataしか見ていない)。
Netdataは今回始めて使ったが、おおざっぱにどこにボトルネックがあるのか分かるので、便利そうだった。(見方を理解していので、全く使いこなせていなかった... 競技中に「なんでこんなにグラフが多いんだ」と愚痴っていた)
まだまだ基礎的な改善をする余地はあったので、一つ一つの改善をもっと素早くやれるようになれば、さらにいけそうだったが、まあ付け焼刃では難しいかろう。

ISUCONは練習をするのが難しいが、参加した大会だとある程度問題が頭に入っているので、他の人のアプローチを見るのが勉強になる。(だから、運営もwrite upを書くまでがisuconです、みたいなことを言っているのだと思う)
他の人に記録を見て勉強しようと思うので、この記録が誰かの役に立てばと願う。

このスクラップは5ヶ月前にクローズされました