なまえは まだ ない

思いついたことをアウトプットします

ISUCON12に出場し予選敗退しました

2年ぶりに参加してきました

7月23日に開催されたISUCON12の予選会に参加し、最終スコア7831点(全体127位)で敗退してきました。

昨年(ISUCON11)はスケジュールの都合がつかず不参加となり、その無念を晴らすべく社内ISUCONを開催したりもしました。

www.wantedly.com

今年はこの社内ISUCONの効果もあってか、比較的最近入社した人が積極的に参加表明をしてくれました。嬉しい限りです。 社内でいい感じにチーム分けをし、私は初参加の2人と共に腐羅亜というチーム名で参加しました。

当日までの準備

私以外の2名が初参加で勝手がわからないということもあり、事前準備は基本的に私が主導して実施しました。 環境構築用のリポジトリによく使うツール類を揃えて、当日なるべく迅速に行動できるように。

例のISUCON本も当然一読し、当日役に立ちそうなTipsをチートシートとしてNotionにまとめたりもしました。 ISUCON本は(ISUCONに出なくても)勉強になるものがたくさんあり、とても良い本だなと思いました。

あと、alpによるアクセスログの集計結果をシュッとSlackに流せるように、簡単なプログラムを書いて公開したりしました。

github.com

類似サービスとしてSlackcatというものがありますが、こちらを会社のワークスペースにインストールすることが認められなかったので、自分で別手段を用意した感じです。

当日の感想

予選に使ったリポジトリを公開したので、気になる方は御覧ください。

github.com github.com

どんなことをやったかをつらつら書いていこうかと思ったのですが、思い返してみたら代表的な改善は全部他2人がやってくれていたので、私が取り上げるべきものはあまりありませんでした。 というわけで当日の感想ベースで書いていきます。

問題について

まさかのISUCONをSaaS提供するシステムが題材で笑いました。普通にほしいです。

競技が始まってからの動き

競技が始まったら他の2人にマニュアルの解読を任せ、私はせっせと環境構築に勤しみました。 とりあえず与えられたサーバーでSSH公開鍵の発行やレシピのクローン、ツールのインストールなど。 このあたりは事前に素振りをしたりチートシートを作っておいたのがとても役に立ちました。

SQLite との会敵

コードをざっと眺めていたら、なんかMySQL以外のドライバーがインストールされてる……と思い、よくよく追いかけてみたら各テナントのDBはSQLiteが使われてるじゃありませんか。 あ、ふーんそういうことね。と、今回の問題の概要を理解しました。恥ずかしながらこれまでSQLiteについて真面目に触れてこなかったので、このあたりで経験不足が重くのしかかる予感がしました。

なかなか上がらないスコア

最初はセオリー通りalpでアクセスログを集計して、重いエンドポイントから順次改善していくことに。

明らかにここN+1問題発生してるなという箇所やこの処理冗長だなという部分を見つけて改善していきましたが、なかなかスコアが伸びない。お、おかしい……。 ベンチを回している間topの出力からMySQLサーバーがCPU150%ぐらい使ってたのは観測していて、「なんでメインのDBじゃないのにこんな使ってるんだ?」と違和感は覚えていました。 この時点でMySQL側のインデックスやID採番クエリといった問題に向き合えれば早かったような気がします。そちらに気が向くのが遅すぎた。

足を引っ張る初期データ

SQLiteのDBは最初から初期データとして100テナント分のDBが存在していました。 SQLite側には一切インデックスが作成されておらず、今までのノリで考えればそこを改善すればスコア改善するだろうと踏んでました。 アプリはベンチマーカーのInitializeが走るたびに初期データをリセットするようになっていたので、Initializeのタイミングで100個のDBにインデックスを作成するクエリを投げる必要があります。 この辺りはこれまでのISUCONの傾向とは異なった部分であり、それなりに手惑いました。

また、途中どう考えてもplayer_scoreテーブルのデータ量が足を引っ張ってると思い、最新スコアだけを格納するテーブルだけを作ろうとかも考えました。 が、やっぱりここでネックになるのは初期データで、100個のDBを上手いことマイグレーションする手立てが思いつかず諦めました。

あとはローカルにDBがファイルとして存在している都合上、アプリとSQLiteがどうしても切り離せない&分散できないというのも悩みのタネでした。 結局アプリ+SQLiteの1号機とMySQLサーバーの2号機という2台構成が限界だったのですが、どうやれば3台使い切れたんだろう……謎です。

MySQLに載せ替えるか、SQLiteのまま突き進むか

SQLiteのデータベースはテナント毎に作成されるにも関わらず、各テーブルになぜかテナントIDを記録するカラムが用意されていました。 この設計は明らかに不自然であり、作問者の意図がプンプン臭ってくるものでした。

これは作問者がMySQLへの載せ替えを匂わせているんだろうと踏み、競技中3回ほどMySQLサーバーにすべてのデータをマイグレーションすることを検討しました。 が、私が試した拙い方法では1つのDB辺り5〜6分の時間を要してしまい、直列で実行したらマイグレーションが完了しないまま競技を終えてしまうことが目に見えていました。 結局私のチームではMySQLへのマイグレーションを断念しましたが、やはりというかそれをやってのけたチームはあったみたいですね。

後々会社の先輩にマイグレーション作業用に強いEC2とかRDSのインスタンスを立てて、その結果を競技用サーバーに持っていけば良かったのでは?」と言われました。

( ゚д゚)ハッ!なるほど!

たしかにレギュレーションをよく読めば、開発のために別のリソースを使うことは全然セーフのようです。

主催者の指示以外で利用が認められたサーバー以外の外部リソースを使用する行為(他のインスタンスに処理を委譲するなど) は禁止する。 ただしモニタリングやテスト、開発などにおいては、PCや外部のサーバーを利用しても構わない。

レギュレーションは把握してたつもりでしたが、そこまでの発想が無かった……。

総括

今年も結局悔しい結果に終わりましたが、8時間頭をフルに使って問題に取り組み、とても有意義な時間を過ごせたと思います。 ISUCONで得た知見・勘は業務でも活かせる部分が多く、今後も会社のメンバーを誘って参加してきたいと思います。 来年こそは本戦出場、そして優勝を目指して頑張りたいです。

最後になりますが、作問や準備、運営をした皆様、本当にお疲れさまでした。 とても楽しいISUCONでした。引き続き本選も応援しています。