Skip to Content

ISUCON12予選に参加した

概要

  • ISUCON12予選に nisshy と参加して(チーム名:NiNo)最高スコアは10500くらいでした(追記:最終参考値は9792でした)
  • 自分はインフラ周りを担当してMySQL移行も行ったものの、MySQL移行だけではスコアは大して伸びず、移行の恩恵を最大限活用できずに時間が来たので結局SQLite3のままでフィニッシュしました

やったこと

SQLite3のMySQL移行に大体の時間をかけたので、移行の部分について書きます

移行すべきか否かの判断

  • コードを読んで、SQLite3を使っていることに気づく
  • 色々問題があることに気づく
    • そのままでは複数台を活用するのが困難
    • トランザクションではなくファイルロックしている
    • テナントごとにデータが分かれている
    • リクエスト毎に接続している
    • MySQLスロークエリの集計に用意したツールが使えない
  • 移行せよと言わんばかりの仕込み
    • クエリに全て WHERE tenant_id = ? が入っている
    • sqlite3-to-sql というスクリプトがある
  • 移行を決める

初期データをMySQLにInsertする

  • sqlite3-to-sql を使って初期データをMySQLに流し込んで見る
    • 370万行ほどあり全く終わらない
  • よく見たら1行ずつINSERT INTOしている
  • bulk insertに変換するためのスクリプトをPythonで書く
    • 単に正規表現で頑張る
  • 370万行のbulk insertを流し込むとallowed packet sizeに引っかかったので、上限を上げる
  • 再度流し込むとhungしてしまう
  • 10万行ごとにファイルを分けて、ファイルごとにcommitする
  • 10minくらいでinsertが完了する

initializeで初期化できるようにする

  • initializeは30秒で完了しなければいけないので、毎回流し込むままだと無理そう
  • 調べた感じ、InnoDBのコールドバックアップが使えそう
  • コールドバックアップのためにはmysqlをstop/start&ファイルをコピーする必要がある
  • スクリプトでやる場合、ホストへのアクセスとsudo権限が必要
  • Docker管理されてるままだと難しそうなのでDockerを外す
    • 言語環境(golang)とmysql-clientをinstall
    • 環境変数をスクリプトにしてUnitファイルに指定
    • Unitファイルの起動コマンドを修正
  • init.sh で mysql stop & /var/lib/mysqlのコピー & mysql start するように修正

アプリケーションコードの修正

  • SQLite3を参照しているところを全てMySQLを参照するように修正
  • ファイルロックしているところをMySQLのトランザクションでロック(Begin, Rollback, Commit)するように修正

トラブルシューティング - Admin用のデータの復元

  • これでベンチを走らせてみるが、返すべきデータが無いという感じのエラーが出る
  • init.shを修正する際にadmin/10_schema.sqlを流すようにしていたが、よく見るとこれは最初の時点では呼ばれていないSQLだった
  • tenantテーブルなどは初期データが外部にはなさそうで、init.sqlで追加分だけ消去していたことに気づく
  • admin/10_schema.sqlを流すことによってtenantデータなどが失われてしまう
  • 他のインスタンスからコピーして復元する

トラブルシューティング - DeadLockの解消

  • ベンチマークを走らせると、CSVアップロードの箇所でDeadLockが発生するようになる
  • よく見るとINSERTクエリが1行ずつになっている
  • 複数のトランザクションが、INSERTクエリで互いが必要なIDをロックしてそう
  • bulk insertに修正してベンチを走らせると、ついにスコアが出るようになる

MySQL移行後の改善

  • 相方がやっていた変更をコンフリクト解消しながら取り入れる
  • BillingAPIが20秒以上かかっていて明らかに遅く、実際competitionごとにデータを取得しているので、一括でデータを取ってくるように修正しようとする
    • 途中で残り時間的に厳しいという感じになり、SQLite3を使うバージョンのまま行くことに決める

感想

  • マシンをセットアップ・ベンチを走らせてプロファイリングする、などはあまり支障なくできて良かったです
  • MySQLだけロードバランスする、なども準備のおかげですんなりできたのは良かったです(ただし最終提出では色々あって結局使わなかった)
  • アプリの挙動をしっかり把握してからMySQL移行を検討すべきでした
    • 初期データは無駄なデータが多そうなので、アプリの要件を先に正確に把握していれば初期データを削減する方法があることに気づけたかも
    • そもそもMySQL移行の前に改善すべき箇所を改善してから移行を検討しても良かった
  • 練習で一切やってないこと(DB移行)を本番でやるべきではなかったです
  • DB移行くらいすんなりできるような実力をつけたいです

今年もとてもおもしろい問題でした、運営さんありがとうございました!