ISUCON 10 予選 参加記

2020年 9月12日 (土) に開催された ISUCON 10 の予選に一人チームで Rust で参加しました
予選突破のボーダーが 2158 点で、自分の最終結果は 1017 点でした
(最終結果一覧)

事前準備

  • ISUCON 9 の参照実装を Rust で書き直す (未完)
    • actix-web + sqlx で実装
    • 半分ぐらい実装して、ライブラリは理解した気持ちになったのと実装がしんどくなったので諦めた
  • ISUCON 9 の予選1日目一位の方の Makefile をパクる
    • Makefile 使うのが辛かったので cargo-make で書き直した
    • オリジナルはサーバ内で使う想定になっているが、全サーバを一度に操作したかったのでローカルから各サーバに ssh して操作する形に書き直した
    • 自分の運用に合わせて幾つかコマンドを追加
  • 設定ファイルの管理
    • 各サーバの設定ファイル (hosts, my.cnf, nginx.conf, sysctl.cnf) をローカルで git 管理するように
    • nginx.conf と my.cnf はデプロイ前にバリデーションをかけるようにした
  • sysctl, mysql, nginx のいい感じの設定を調べる
  • nginx でのロードバランシング、mysql のレプリケーションを素振り

当日やったこと

  • sysctl, mysql, nginx に設定ファイルにいい感じの設定を入れる
  • スロークエリを確認しながら index を貼る
  • nazotte の内包判定をアプリケーション側で行う
    • 判定のために SQL クエリの発行が行われていたので修正
    • 競プロっぽいなと思いつつ NTTPC さんの記事 を写経した
    • 絶対バグらせる気がしたが、オリジナルとAPI のレスポンスを比べて diff がなかったので恐らくバグってないはず (1ケースしか試してないけど…) (ベンチも通ってるので多分大丈夫)
  • 物件のレコメンドのクエリを修正
    • ドアサイズを絞るために無駄な OR があったので消した
      • width, height の大きい方を door_size_0, 小さい方を door_size_1 としてカラムを追加
      • 椅子の w, h, z の一番小さいものを door_size_1 と比較, 二番目に小さいものを door_size_0 と比較する
    • 結局いい感じに index に乗らなかった (SQL の知識が足らずここで諦めてしまった)
  • Bot を nginx で弾く
    • ドキュメント記載の Bot の正規表現は PHP preg_match() に準拠してそうだった (勘) ので、php 正規表現チェッカー で確認しながらテストした
    • nginx の if で使える正規表現の理解が足りず、弾くとまずいものまで弾きそうだったので、幾つかのパターンは無視した
    • actix-web の Guard を一瞬使おうとしたが正規表現に対応して無かったので諦めた
    • スコアに影響するパス ( /api/chair/buy/{id} , /api/estate/req_doc/{id}) は Bot でも通すようにした
  • サーバ構成の変更
    • mysql の CPU 使用率が 90 % ぐらいで張り付いていたので、DB の分割を試したが上手く行かず
      • Write 1 台, Read 2台でレプリケーションを試したが、遅延のためかベンチマークが通らず… (時間が足らずちゃんと確認できてないので別原因かも)
      • アプリケーションの修正も含めてかなり無駄に時間を使ってしまった
    • 仕方ないので以下の構成で妥協した
      • 1: nginx + app
      • 2: app
      • 3: mysql
    • テーブル毎に DB 分割思いつきたかった… (悲しい)
  • 再起動試験
    • 不要なサービスの自動起動を無効にして、全台再起動後にテスト
    • コンテスト終了後の再テストで出たスコアが最終結果になると勘違いしており、ここで下振れたスコアのまま放置してしまった
      (もともと 1240 点ぐらいで -200 点ぐらい下振れてて悲しかったが、結局予選通ってないのでまあ)

良かったこと

  • Rust で参加
    • これまで Python で参加していたが、あまり書かないので読むのも書くのも脳死でできず辛かった
    • 最近割と Rust を書く機会が多く、割と習熟できていたのでアプリケーション周りで詰まることは無く良かった
  • 事前に用意した Makefile
    • ほぼ必要な操作を網羅していて、それらが脳死でできるのでかなり楽だった
    • kataribe と pt-query-digest スゴイ
  • 一人参加
    • 必然的にすべての部分を見ないと行けないので、自分に足りない部分が明確になってよかった
    • コミュニケーションコストが無なのでそこはかなり楽だった

反省点

  • SQL 周りの知識不足
    • スロークエリを直す作業で、なかなか index に乗ってくれず辛かった
    • 作業時間的にもここがボトルネックになっていた
    • データベーススペシャリスト試験受けるか
  • インフラ周りの設定の知識不足
    • パラメータが与える影響の理解が不足していて、問題に応じた調整が全然できなかった
    • 過去問で練習したい
  • Rust のパフォーマンス測定
    • いい感じに測定する方法がわからず今回は諦めてしまった
    • 直前に pprof-rs を試したが、使いこなせる自信が無かったので本番では使わなかった
    • NewRelic APM, Rust にも対応してくれ〜〜
  • 設定ファイルの管理
    • etckeeper というのがあるらしいので今度使ってみる
  • アプリケーションの並列処理
    • 今回使わなかったが、もっとラフに入れていっても良かった気がする

感想

予選突破できず悔しかったですが、ドチャクソ楽しかったです
誘う人いないので来年も一人枠を残してほしい…