ISUCON
ISUCON10参加記
公開日:
2020/09/28
ISUCON10参加記

こんにちは。pngnです。今回チームpngnでISUCON10に参加し、見事予選敗退したので記念に参加記を書こうと思います。正直に言うとプロの方が見て得られる様な事は何一つ書かれていないと思います。主に布教用。

ISUCONとは

いいかんじにスピードアップコンテストの略。とても人気で一瞬で予選の枠が埋まった。具体的には遅いWebサーバーのプログラムが与えられるのでそれを改良して高速化する。捌けた数に応じて得点が得られてそれで競う。サーバー3台与えられ、自由に役割を決めてよい。

LineやCookpadなどの有名な大企業が主催してる。

予選前にやったこと

最低限の知識の整理

Nginx

リバースプロキシ用。このURLに飛んできたらこのサーバーのこのポートのプログラムに渡すとかを設定。

アクセスログ解析ツールの知識(alp/kataribe)。これを見てどこがボトルネックかが分かり修正すべき所が分かる。

その他諸々の設定。http2を有効にしたりtemp fileの生成を抑えたり...

Go

Webサーバーの言語。PHPやnode、Rustなどから自由に選べる。Goは速いから選んだ。先輩のチームはPHPで出場したらしいが、PHPでは初期スコアが300点なのに対してGoは400点程度だった。

実はGoは使ったことが無く、前日にGoのTutorial読んでた(は?)

MySQL

データベースの言語。基本戦略はよく参照されるものにindexを貼る。for文の中でクエリが呼ばれると通信etcに時間がかかるので可能ならまとめてクエリを投げる(N+1問題)。変更がかからない部分はインメモリキャッシュで高速化。

pt-query-digestでログ見る。

その他

netdataでサーバー負荷を監視できる。

過去問環境の構築

GCPの無料枠が余っていたのでサーバー3台借りて過去問の環境を作った。割と面倒なのでやってみた方がいいかも。本番環境は既に大抵のソフトはインストールされている。また、nginxは既に動いていて、ベンチマーカーはport80に飛んでくる(準備の段階でよく分からなかったので...)。あと、メインのプログラムは最初からデーモン化されている。

問題

椅子と部屋を売るらしい。というか過去問そのうち上がるだろうからそれ見てくれ。

競技中

まず、踏み台サーバーを経由してsshする方法を知らずに1時間近く右往左往していた(は?)。ssh -L 8080:localhost:80 serverでサーバーに接続しつつサーバーの80番ポートをローカルに8080に転送できるらしい。それでブラウザでlocalhost:8080にアクセスする事でテストが出来る。参考までに、コマンドのlocalhostはサーバー側にとってのlocalhostという意味っぽい?

サーバー構成をNginx(アセット) + Chair専用(Go + MySQL) + Estate専用(Go + MySQL)で分割した。これは他の人のブログを見る限りそこまで悪手では無かった気がする?今回はデータベースがボトルネックになっていた様なのでデータベースサーバーを2台に分ける方が良かったかも???netdataをもっと見るべきだった。

SQLにindexを張る操作はチームメイトにまかせた。

ところどころSQLの効率が悪い部分を修正したりしていた。

結果(追記)

一時は900点台を出したが直前ギリギリのごちゃごちゃ変更で400点まで落ちた。初期スコアとあんまり変わらなくて悲しい。(900点取れた所で平均以下なんですけどね...)

データベースの初期化に失敗してるっぽくて0点を連発していた。最後の400点もデータベースの整合性が取れて無くて減点されていた気がする。

反省点

圧倒的知識・経験不足ッ!!!

Go初心者なので、コードをスラスラ読めなくて、またネットワークを構築するのに予想以上に手間取ってコードの全体像を把握出来なかった。そもそもあまり他人のコードを読む機会が無いのがダメな気がする。

MySQLに関しても同様。来年までに修行してまともに読み書きできるようにしたいです。

あと、諸々のツールを自動でインストールするスクリプトを書いた方が良かった。

出てよかったと思ったこと

GoやMySQLを勉強するきっかけになったのは良かった。MySQLは昔バイトで触った事あったけど、ここまで効率を意識して書いた事が無かった。

今回サーバーの構成を重点的にしたが、サーバー構築(ストレスたまるが)楽しいし勉強になった。

クソコードと良いコードでここまでパフォーマンスが変わるという現実を思い知った。パフォーマンスが2倍変わると単純計算でサーバー費が1/2になるわけで...しかもサーバーの台数が増えるごとにシステムが複雑になってよりパフォーマンスが落ちるので...

来年出たい人に向けて

最低限のShellが触れないと難しそう。ソースコードの編集などはVSCodeのSSHプラグインなどを入れてGUIで出来なくもないけど...

面白いから是非出てみて!Webに対する理解も深まってよきです。(ただ出るならちゃんと対策しようね)

(蛇足)競技プログラミングのススメ

ISUCONも競技プログラミングの1種ですが、ここでは特にAC/WAを競うコンテストの話をします。

他人と競争する事に抵抗感がある人もいると思いますが、僕が競プロを勧める理由はロジックをシンプルに捉えて、シンプルなコードが書けるようになる事だと思います。(もちろんアルゴリズム的な話もありますが)

例えば今回以下のようなコードがありました。

w := chair.Width
h := chair.Height
d := chair.Depth
query = `SELECT * FROM estate WHERE (door_width >= ? AND door_height >= ?) OR (door_width >= ? AND door_height >= ?) OR (door_width >= ? AND door_height >= ?) OR (door_width >= ? AND door_height >= ?) OR (door_width >= ? AND door_height >= ?) OR (door_width >= ? AND door_height >= ?) ORDER BY popularity DESC, id ASC LIMIT ?`
err = db.Select(&estates, query, w, h, w, d, h, w, h, d, d, w, d, h, Limit)

明らかにヤバイコードですが、皆さんならどう直しますか?これは結局の所、w, h, dのうち2つを選んで作られる長方形より大きいものを選んでいる訳で、w, h, dの中で小さい2つを見ればいいことが分かります。なので簡易的にバブルソートをして

if w > h {
  w, h = h, w
}
if h > d {
  h, d = d, h
}
if w > h {
  w, h = h, w
}
// w <= h <= d
query = `SELECT * FROM estate WHERE (door_width >= ? AND door_height >= ?) OR (door_width >= ? AND door_height >= ?) ORDER BY popularity DESC, id ASC LIMIT ?`
err = db2.Select(&estates, query, w, h, h, w, Limit)

みたいなコードで出来ます。(より良い書き方はありそうですが...)

別に競プロやらなきゃ身に付かないってものでも無いと思いますが、効率的に身につくんじゃないかなーと思います。

競プロもISUCONも開発も、みんな興味のある事には貪欲に手を出していこうぜ!

一緒に読まれている記事
記事がありません。