ISUCON10生は2度目です

TL;DR:

お前だれ

俺は梅の仁。特にとりえもない平凡な男子大学生だ。ある日大学への道を歩いていたら、トラックにはねられて異世界転生しちまった。転生した世界は魔法、剣、そして椅子が存在している世界で、美男美女の椅子に言い寄られる羽目になっちまったぜ。彼/彼女たちに、ちゃんとドアに入る家を案内するために、俺はisuumoを開発することになったんだ。こうなったら、現代エンジニア知識で無双してやる!

ちゃんと書け

こんにちは、皆さんにももう知っていただけていることと思います、梅の仁です。去年、ISUCON9でなんやかんやあって本戦に出ていました。しかし、スコアは振るわず15位。本当に悔しい気持ちを抱えながら今年の7月を迎えました。

「上限」が目に飛び込んできて、もうね、秒だよね、秒。絶対に参加したい思いを抱えていたので、1人でもいいからと申し込みをし、去年のメンバーであった@jumon_jp@ushitora_anqouを誘いました。すぐに快い返事を頂け、院試や研究といった勉強をしつつ、ISUCONへの気持ちを高めていました。2人のステータスはこちら。

  • @jumon_jp
    • ナウでヤングな音声処理の達人
    • すごい猫
    • アプリ(Golang)をお願いしてた
  • @ushitora_anqou
    • コンパイラと論理学の名人
    • GPAポケモンの開発者(それが紹介でいいのか?)
    • すごい深海魚
    • アプリ(Golang)をお願いしてた
    • チームビルドをした
    • インフラを眺める人
    • discordのサーバーでふざける人

前日まで

ISUCONの練習と称して、ISUCON8予選とISUCON9本戦のインスタンスを建て、チームメンバーと色んなツールを動かしたりする練習をしました。

ソースを読みながら頑張って建てたISUCON8の予選ポータルサイト。大変だった

前日までこれに参加していたので、予選前日は疲労困憊で早めに就寝。見事朝7時に起きたのでISUCON優勝です。そして1時間後にこのようなアナウンスが来ました。

もう2時間寝たくなりました。さすがに起きておこうと思い、コーヒーを体に流し込みました。

競技開始

12:30 競技開始

さて、Ansibleを使って、用意していた初期化や「いつものツール」を入れるやつをやりましょう!

…できんのだが?てかwslからはsshできるんだけど、え、なんでwinからだとssh出来ないの?は?

どうやら原因はここだったみたいなのですが、焦りに焦ってAnsibleの内容を手で実行する羽目になりました。それに、win上からVSCodeでsshもできなくなったため、自動的にssh上でrawなvimを使うことになりました。本当につらかったのですが、まあどうにかなるにはなるので、まずは各サーバーにswapを作りましょう。

sudo dd if=/dev/zero of=/swapfile bs=1M count=4096

所で、df -hの結果をご覧ください。

/dev/vda1       9.6G  8.7G  917M  91% /

なんと全体が10GBしかないんですね。4GBもスワップを作ることは不可能でした。disk fullを起こしてしまい、「やばいサーバー死んだらやばい」とすぐに rm -f /swapfile。めちゃくちゃ焦りました。良い子は空き容量を確認してからswapを作りましょう。その後いつものツールなどを投入しながら、マニュアル読みを2人にお願いしていました。アプリの仕様を知らないため、「なぞって検索がやばい」というメンバー2人の会話を、「『謎って検索』するってなんなんだ…?曖昧検索かfeeling lucky…?」と思いながら作業していました。

13:00- nginxないし開発環境整備

nginx.confのひな型を導入し、デプロイのための環境を用意していました。後ろで最初のベンチマークが走っているのを聞きながら、「MySQLのCPU負荷がすごそう」みたいな話を聞いていましたが、「CPUだったらappな気もするなあ」などと発言していました。この後すぐ、その見立ては外れます。ここでコーヒーブレイク。

13:30- mysql設定投入、stock

mysql.cnfのひな型を投入し、slowqueryを眺めることに。どう考えてもやばそうなクエリのオンパレードでめまいがします。これはいかんとMySQLWorkbenchをつなげ、ER図を取ることにしました。案の定初手はつながらなかったため、 bind-addressをコメントアウトし、権限が足りないと怒られたため、権限付与を行いました。そして現れるこれ。

クソでかテーブルが2つ、インデックスがない。ああ、神よ。

もうめまいですよね、めまい。コーヒーを飲みます。「どう考えてもMySQLのCPUやば~~~~!!!!!」となり、急いでslowQueryを考えることにしました。
クエリを眺めてるにあたって、あまりにも stock > 1のWHERE条件が多く、indexが効かせにくい、indexよくわからん問題に出会いました。@jumon_jpと一緒にstockをDBから外し、インデックスをそれに合わせた構成にしました。

14:30- ずっとMysqlと向き合う

マジで何にもわからん。テーブルが参照系が多いようなので、インデックス貼って貼って、貼りまくって、クエリが使われてる文脈を聞いて、貼って、貼って、消して…それを繰り返していました。
クエリを眺めている途中で、椅子がドアに入るように回転させ、6個もOR条件を発行するわけのわからんクエリを発見。@jumon_jpに競プロっぽい解決をいい感じにお願いしていました。また、なぞって検索を良しなによくするのを@ushitora_anqouにずっとお願いしていました。

16時も近づいてくると、どうしてインデックスを貼っても貼ってもうまく動かないのか、見当がつくようになってきました。大体、ユーザーの入力条件によってWHERE句の中身が変わり、DESCオーダーとASCオーターの組み合わせを行うのじゃ、WHERE句の条件が選択的だったり選択的じゃなかったりします。なぞって検索で、クソ小さい丸を書いたならindexが効くかもしれませんが、クソ広い丸を書いたならindexが効く理由がありません。optimizerが、インデックスを使うより、全件検索を行うが良い、と判断するようなユーザーの入力もあるでしょう。どうしようもありません。@ushitora_anqouと「検索はクソ!!!!!」と叫びながら、インデックスじゃどうにもならんケースも多そうだと感じていました。そう思いつつも、よく来るようなクエリの組み合わせで、かつ、「条件が絞り込めそうなクエリ」にindexを貼っておくことにしました。それでも全く減らないCPU負荷に焦りを抱えていました。

17:30- 複数台構成・mysql8導入

optimizerの改善と、desc indexの利用に期待し、mysql8にあげる決断をします。ですが、あらかじめ複数台構成を始めよう、と決めていた時間が迫ってきていました。私がインフラ担当なので、本来なら複数台構成は私がやるべきなのです。ですが手が足りず、@ushitora_anqouに依頼しました。(本当にごめんなさい)その傍らで、mysql8のアプデを行いました。アプデ後、すぐに設定をチューニングし、DESC indexを使うと点数が良く伸びました。

それでも劇的な伸びとは言えず、CPUは100%に張り付いたまま。ここらへんからつらくなってきました。去年はなんやかんやありつつ本戦出たんですよ。今年こそはと1年間、いろいろなことの合間合間にweb系に触れ続けてきたんです。誘った側としても、web系ちょっとは触ってて、インフラ担当って名乗ってる人間としても、ISUCON大好きな私としても。予選落ちしたらチームメンバーに申し訳立たねえよマジでどうしようかと思い始めます。

そんな思考はさておき、@ushitora_anqouとDBの根本的な相談をします。「インデックスを貼ったうえでもどうも無理なリクエストが出うる」「多角形の内側を判定する部分をどうにかできないか」「latitudeとlongtitudeの絞り込み問題で何とかインデックスが効くようクエリを分割できないか」などと会話をしました。MySQLのレプリケーションを行って、Read SlaveとMasterにわけ、負荷分散を行うといいのでは、という結論になりました。ですが、インフラ担当の癖にレプリケーション、やったことないんです。残り時間も少なくなり、見送ることにしました。

20:00- カーネルパラメーター調整

もう最後のダメ押しだと、mysqlサーバーのカーネルパラーメーターをチューニングし始めます。ですが全く意味はありません、なぜならCPU負荷は下がってないからです。iowaitだって出てないのです。ですが焦ってしまい、知ってる手法で早くなることを願ってしまいました。

「推測するな、計測せよ」

本当にこの一言に尽きると思います。案の定スコアは変わらず、再起動試験の時間を迎えました

20:30- 再起動試験、ガチャ

再起動試験をします。あらかじめチェックすることをチームメンバーが記述してくれていたので、滞りなく再起動を行えました。振り返ってみると、個人が検証用にfailしたことはあったものの、全員の成果を組み合わせたベンチは一度もfailすることなく進められていました。それもあって、再起動後に動きさえすれば、再起動failにはならないだろうとメンバーを信頼していました。

そしてISUCON名物ベンチガチャ。あまり振れ幅が変わらなかったものの、まあ最高点に近い点数で撤退。「DBの負荷どうやって下げたら良かったんだろうなあ」「わからんねえ」「わからん」と言いながら、ISUCON10予選を終えました。冷たかったコーヒーはすっかりぬるくなっていました。どうやら500mlぐらい飲み干していたようです。

21:00 – 0:08 そして

雑談をしたりしなかったり、寝たり寝なかったり、ご飯を食べたり食べなかったりして、運営の皆さんの動向を監視していました。discordのrandomにはいろいろな人の感想が流れてきたので、「うわーそれは賢い」「それも賢い」「すごい」「なんやねんその概念」とわいわいしていました。圧倒的なDB律速、そしてその対処のための知識の奔流に、まだまだ若輩者だと実感させられました。特に、「テーブルごとにDBを分割する」アイデアは本当に素晴らしいと感じました。なんで気づかんかったんやろう。@ushitora_anqouと私で悔しがっていました。

0:00を回り、運営の皆さんの終電が心配されるようになったころ、運命の時間がやってきます。最初少し聞き逃したため、一般枠の25位までをよく理解しないまま、941さんのひとこと「計算機科学実験及演習5」。ああ、学生枠2位です!!!本当にうれしかったです。

去年は本戦に出れて「ラッキー」でしたが、今年は正直安心しました。チームメンバー全員そろって本戦に出れるわけです。本当に、本当にうれしかったです。

悔いのない本戦を戦いたいですね。そして、できれば良い成績を。本戦をご一緒できるチームの皆さんと戦えることを待ち望んでいます。

そして、大変な思いをされ、終電を心配され、深夜の3時に起きてる運営の皆様。本当にお疲れ様です、そして、ありがとうございます。めいっぱい楽しい思いをさせていただきました。本戦でも楽しませていただきます。本稿が少しでも大会を盛り上げることを願って、締めとさせていただきます。

末筆ですが、読了ありがとうございました。