概要
先日行われたISUCON13に参加しました。
特別な取り組みはしていないのですが、初参加の備忘録として残しておきます。
準備期間
エントリー
9月上旬にTwitterで「ISUCON面白そう~」と呟いたら競プロ友だちに誘われたので、参加することにしました。
エントリーが先着ですぐに満員になるのでのんびりしてると0次予選落ちします。1分くらいは猶予あるので推しのグッズを買うつもりで開始前からPCの前に張り付いていれば何とかなると思います。
9-10月
チームメンバーは20代ITエンジニア×2人と情報系学部1年生×1で、3人ともISUCON初参加です。とりあえずISUCON本を買って読みました。過去の解法ブログを読むと知らない技がザクザク出てきて、ISUCON常連勢とは相当距離があるなぁという感じでした。初参加ということで参加者平均順位くらいを目指すことにしました。
また、ISUCONの利用言語比率によるとGoが大人気だったのでGoを使う想定でたまに触っていました。
11月
とりあえずISUCON本をなぞってprivate-isuで遊んでいました。
それから、自分が業務でやらない基本所作を身体に馴染ませる必要がありそうだったので、AWS上でprivate-isuの環境を何度も用意したり、EC2にNginxやMySQLを入れていろいろ設定を弄ったりしていました。
ここで過去問の出題動画を初めて見ましたが、凝っててめちゃめちゃカッコイイです。
11/21-24
そういえばチームメイトと役割分担などを決めていないということでdiscordを動かし始めました。2ヶ月前に決めておくべきです。
当日の動きについては2人がサンリオピューロランドでデートしているのを邪魔しながら前日の午後になってから決め始めました。1か月前に過去問でチーム練習しておくべきです。
当日
できたこと
- 初動がスムーズだった
- 全員10時前に起きた
- AWSの環境構築、ブラウザ実行、sshログインに誰も詰まらなかった
- update, alias, バージョン管理、全体構造把握など
- スロークエリログや実行計画に基づいた基本的な改善に取り組めた
- index貼る
- N+1問題の解消
- 不要なデータ取得の解消
- 基本的なコマンドやログの読み方でググらず進めることができた
- いろいろ小さなトラブルがあっても何とかできた
できなかったこと
- DNS水責め攻撃対策
- キャッシュの活用
- その他上位勢がやっているあらゆること
時系列
10時-11時
- 問題をよく読む
- 環境構築する
- http, sshで接続確認
- ベンチマーク初回実行(10:43)
- 3470点
- Git initする
- ログを仕込む
- ベンチマーク再実行(11:00)
予定通りのことをしました。
11時-14時
- テーブル構造やアプリケーションを理解していく
- スロークエリログを読んでインデックスを張る
- 8868点
- DNS水責め攻撃について考える
DB、SQL関連の改善はデータベーススペシャリストの自分がやるつもりでいましたが、途中で学部1年生の頼もしいチームメイトがインデックス貼りやN+1解消を積極的に見つけて実行も買って出てくれたため、任せて自分はDNS水責めについて考えることにしました。
解消することで改善するスコアが見積れず着手するべきか確信が持てませんでしたが、問題文でも強調されており、これとかこれをググって読むことを想定されていそうだったため、ネットワークスペシャリスト1の自分が工数を割いてみることにしました。
14-16時
- 実装をPythonに切り替える
- 3300点
- コードをいろいろ弄って改善する
- 5000点
- DNSはどうにもならず……
僕がDNS水責め攻撃の対策を検討し、チームメイト2人がコードを弄る分担になりました。
ここで実装をPythonに切り替えることになりました。僕以外の2人はPythonのエキスパートで、競技プログラミングでPythonの高速化にも慣れていた2ためです。Pythonが遅いといっても点数の差は初期値で2倍弱なので、アプリケーション改善で伸びるスコアに比べればさしたる差ではないという判断でした。
途中でサーバーに接続できなくなり再起動するなどのトラブルもありながら、Pythonのスコアは(Goで8868点の状態の)3300点からいくらか伸びましたが、コードに手を加えていないGoに遠く及ばず、何ともでした。
また、DNS水責め攻撃への対策は想定スライド(?)を読んでいろいろ実験していたものの、正当なサブドメインも多いしどうするんやという感じで、解決の見込みがないと16時で判断して撤退しました。
16-17時
- 3人でアプリケーションとDBのチューニングを頑張る
- 5500点
- 競プロPython典型「PyPyを使う」などをやる
- スコア下がりました
もう大掛かりな変更は厳しいので、実行計画を見ながらインデックスを最適化したり取得するレコードを絞ったりしていました。
しかしお昼のGoの8868点を超えられず、苦しみました。
17時-17時半
- 動く状態で作業を中断する
- ログを切る
- レギュレーションを再確認する
- 再起動の準備をする
17時半-18時
-
ここで唐突に実装をRustに切り替える
- もちろんPythonで実施した改善の移植は間に合わない
- 11705点
Rust最高!1番好きな言語です。
結果
11705点で201位でした。
694チーム中、追試で失格にならず正の得点を取ったのが507チーム。
10000点以上が252チーム、30000点以上が66チーム、50000点以上が29チーム、1位が468006点です。
反省
当日を振り返って
- 14時あたりまではぶっつけ本番の初参加にしては妥当なムーブができていたと思います。
- DNS水責め攻撃対策に突っ込んだこと自体は、それっぽいスライドを見つけて着手できそうだった以上は仕方ない判断だったかなと思います。上位争いをするチームであれば「経験のないことはやらない」「計測でボトルネックと判明しないうちはやらない」という戦略もあると思いますが、そもそも我々は経験のないことばかりなので……。まぁキャッシュ活用は典型なので事前に「経験があること」にしておいて当日はそちらから手を付けるべきでしたが。
- DNS水責め攻撃対策で撤退まで2時間使ったのは失敗でした。1時間で「今回の仕様でこの方針をやりきるのはトップ30レベルのチームでも難しいのでは?」という感覚はあった3ので、その時点で諦めてサーバー切り分けなど確実に多少マシになる方針に切り替えていれば成果ゼロにはならなかったはずです。
- Go→Python→Rustと迷走したのは、単純にチームで過去問練習ゼロで挑んだのが敗因です。Goのコード修正にPythonほど自信がありませんでしたし、Pythonが最終スコアでどのくらい不利になるかという肌感もありませんでした。Pythonに入れた改善をGo(かRust)に入れると30000点を超えるくらいにはなったみたいです。
うちのチームのポテンシャルでできたのはそこまでで、あとはまだまだ地力不足・手数不足って感じでした。
50000点を超えるまででもアイコン取得処理の高速化をやっておく必要があったと思いますし、他にもISUCON鯖の雑談チャットや参加記を読むといろいろ気づかなかった手筋があり学びが多いです。
次参加する際はやること(本来は今回やるべきだったこと)
バックエンドの基本的なスキルを再学習する
今回も5日前から「AWSでEC2を立ててApacheの前にNginxをリバースプロキシとして置いてアクセスしてログを取る」「MySQLインストールからテーブルいろいろ作成してインデックス貼ってSQL書いて実行計画を見てみる」のような教科書のハンズオン的な素振りで指先を温めていましたが、その延長です。
ISUCONのためというよりエンジニア基礎力の向上として、ISUCON本やtraPの講習会資料の個々の技術が息を吸うように使いこなせるくらいにはしておきたいです。
また、Goの素振りもすべきです。
個人のISUCON力を高める
過去問、参加記、上位チームGithubリポジトリを読み、自分でも手を動かしてみて、手数を増やしていくと良さそうです。
気力があれば実際に時間を掛けて自分1人で過去問に取り組みたいですね。
更に余力があればISUCON本の付録にあるようにベンチマーカーを再実装するのも面白そうです。
チーム練習をする
ぜひ休日1日掛けてやりたいところです。
上位常連チームの記事を読むと、進行や役割分担が洗練されていたり、秘伝の設定ファイルや快適なデプロイ手段が作りこまれており、本気で入賞を目指す際にはぜひ取り入れたいと思いました。
過去問演習については公式から丁寧な環境構築の案内がある他、ISUNARABEという非公式練習プラットフォームもあるようです。
最後に
いつもの業務やAtCoderとは異なるゲームを楽しむことができ、また良い勉強をさせていただくことができました。さくらのクラウドとAWSのクーポンもありがたく使わせていただきました……ビッグ感謝です!
ISUCONはバリバリのバックエンドエンジニアの腕試しにはもちろん、学生や非Web系の人がWebアプリケーションを楽しく安全に弄って壊して学べる教材としても優れていると感じました。オススメです。
-
実は風邪で受験できなかったネットワーク素人なので、何の成果も得られませんでした…… ↩