ISUCON13に初参加しました (26,597点)
こんいす〜。社会人一年目をしているえじっさです。
新卒研修のハッカソンで作ったモックアプリに alp で負荷テストをして、 ngrok のキャパシティーや python の DB のセッションタイムアウトを調べたりしたのがきっかけとなって、会社の同期の かじくん, おかち と ISUCON13 に参加することになりました。
チーム名は合宿時に遊んでいた overcooked!をもじって overcached!です。 overcooked!は料理最適化ゲームなので ISUCON と親和性が高いです。 言語は Go を使っています。
毎週ゆるく就業時間後に同期と集まりながら勉強会をして半年、結果は 26,597 点で 75 位でした。 出場前は「半分以上狙えるといいね〜」って話していたので予想以上の出来でした (今年の参加チーム数は 700 弱くらい)。 来年は入賞 30 位以内を狙いたいです!
当日の様子
当日のスケジュールを書き起こしました。振り返ってみてもとても楽しく充実した一日だったなと思います。
9:30 朝ご飯食べる
会議室に集合して朝ご飯を各々で食べました。
9:40 くらいに youtube 配信が始まっていることに気づきました。
10:00 競技開始
競技開始となり三人で準備しました。 役割はこのように分けていました。
- deploy 用 Makefile 調整、秘伝のタレ注入 (かじくん)
- ansible で計測系ツール (netdata, pt-query-digester など) と memcached 導入&「アプリポチポチ」とチーム内で呼んでいるアプリへの理解を深める作業 (えじっさ)
- レギュレーション読みと CRUD 図作成 (おかち)
今回は本戦が無いということもあり、エンドポイント数とテーブル数が過去の問題より比較的多い印象を受けました。そこでおかちが CRUD 図を手作業で作成するのを止めて自動生成をしてくれていました。 ナイスですね。
自動生成は mazrean さんの isucrud を使っていました。ここで初めて見たのですがとても便利でした。
11:30 秘伝のタレと livestreams_tags にインデックス (5361 点)
秘伝のタレと livestreams_tags にインデックスを貼って、初期スコア 3982 点から 5361 点まで伸ばしました。 ここでしれっと webapp/sql/initdb.d/10_schema.sql のスキーマ作成を webapp/sql/init.sql に移動しておいてくれていました。
13:30 icon の DB 外だしと if-none-match のハッシュ値事前計算 (6956 点)
icon の画像を DB から取得している部分が重かったので、ファイルに書き込んで go で配信することにしました。 本当は nginx で配信したかったのですが、If-None-Match の照合部分をする必要があったので、nginx で配信する方法が分かりませんでした。
今回は HTTP リクエストヘッダの If-None-Match を見て、icon のハッシュ値と同じであれば 304 を返すことができたので、 先にアイコン画像の SHA256 値を計算して DB に保存しておくようにしました。
14:30 DB に色々インデックスを貼る (スコア不明)
slowquery ログを見ながら users や livestreams, livecomments, reactions にインデックスを貼りました。 なかなかベンチが回せなかったためスコアの計測はできませんでした。
14:30 fillLivestreamsResponse, fillUserResponse をキャッシュ、tag をアプリ側にハードコーディング (12976 点)
かじくんが fillLivestreamResponse と fillUserResponse を memcached にキャッシュする実装をしてくれました。 tag は Write がなかったのでアプリ側にハードコーディングさせていました。 ここで、“Q&A セッション"というタグがフォーマッタによって"Q & A セッション"と&の間に空白が入ってしまい、不定期で fail するようになってしまいました。 16:30 に原因が判明したのですが、このバグの修正に二時間以上使ってしまいました。
このタイミングで一瞬 youtube の実況中継のスコアボードに 19 位で載っていました。
17:00 ライブ統計計算のスパチャ計算部分をキャッシュ&NG ワード判定をアプリ側へ (18486 点)
ライブ配信のランキング計算部分のスパチャの合計金額計算の部分をキャッシュするようにしました。 NG ワード の部分でスパチャのコメントを削除する必要があるときにはキャッシュされた合計金額も差し引くようにしました。 その過程で NG ワードの判定部分をアプリ側へ移動させました。
17:40 DB 分割 (26400 点)
アプリ一台, DB 一台に分けました。 DNS の DB はアプリの方に載っている状態でした。
18:30 競技終了
netdata や nginx のログの吐き出しを止めて再起動試験をしました。 終了 10 分前にベンチをもう一度回したら若干スコアが上がったので最終スコア (26597 点) としました。
感想
一ヶ月に一度過去問を開けて模試をして、その後はそれぞれのペースで復習をする感じで勉強をしていました。 定期的に会って勉強会をする同期に恵まれていてとても良かったなと思います。
今回の競技では DNS の部分は全く手つかずの状態で、インデックスすら貼っていない状態で終わってしまいました。 計測をしていてスロークエリログの上位 2 つが両方 DNS の名前解決部分(合計 25%くらいを占めていた)であることは分かっていたのですが、時間が足りず手を入れることができませんでした。 最終的に二台構成にしたときにはアプリ側のインスタンスの CPU 使用率が 100%に張り付いていて、その半分が DNS の DB となっていました。
来年はもっと手数を増やしたいです。