ISUCON7 本戦スコア0

11/25にLINEの新宿ミライナタワーオフィスで開催されたISUCON7本戦。 結果としては最終スコア0(おそらくベンチマーク後の整合性チェックでfail)だった。 チームはfujiwara組。

やったこと

自分がやったことのメモ。

役割分担

これは予選と変わらず。

  • fujiwara=サーバー上の操作・サーバーリソースチェック・ベンチ挙動のチェック
  • acidlemon=サーバーリソースチェック・変更実装
  • handlename=変更実装

レギュレーション確認

今回はレギュレーションが長かった。 PDFで総15ページ。 まずはこれを読み合わせるところから。

初期ベンチ実行

Go実装での初期スコアは3472。

m_timeテーブルを使わない

唯一元からmysqlに入っているm_timeテーブルのレコードが13行しかなかったので、 これをコードに埋め込んでしまってmysqlとの通信を減らす。

部屋ごとにアプリケーションサーバーを固定

別のroomとのデータ共有は一切発生しないという仕様だったので、 オンメモリ化をしやすくするためにroom idでロードバランスすることに。

ベンチマーカーから通信を受けるサーバーは1台だけにして、 そこから3台のサーバーにWebSocketの接続先を割り振る方式。 はじめは、

  1. room idの5文字目(先頭の4文字はROOMで固定)のASCIIコード取得
  2. 3で割ったあまりでどこに割り振るか決める

という適当実装だった。 その後張りふりを均等にするために、

  1. ラウンドロビンで接続順にサーバーを割り振り
    • room idと振り分け先サーバーの対応をメモリ上に持っておく
  2. 2回目以降の接続ではメモリ上に持っていた振り分け先を返す

という方式に変更。

メモリ上のデータの永続化

各種オンメモリなデータを永続化。 実装としてはコード上のstructをencoding/jsonでjsonにして、 一定時間おきにファイルに書き込むだけ。 起動時にこれを読み込む。

ファイルがない場合のことを考慮していなかったり、 メモリ上にデータが無い場合のシリアライズがいまいちだったりして デプロイ完了するまでに手間取ってしまった。

GetPrice, GetPowerのテーブル化

毎回固定値で計算し直しているを、アプリケーション起動時にまとめて計算→リクエストがあったら対応するものを返す。 これによりmath/bigの計算が格段に減った。

あとで調べたらこの変更以降テストが失敗していた。 原因についてはまだ調べきれていないので、時間があったら見る。

github.com/pquerna/ffjson への置き換え (未完)

encoding/jsonの3倍速いというffjsonへの置き換え。

結局うまくいかず、時間を無駄に使ってしまったのが。 詰まったらさっさとチームメイトに相談するべきだった。

  • ffjsonを使ったことがなかった
  • ffjsonはmainパッケージに書かれているstruct定義には使えない
    • 今回のアプリケーションは全てmainパッケージに書かれている
    • パッケージを分離する書き換えが必要
  • 元のコードにある自前実装のUnmarshal関数とffjsonがgenerateするUnmarshal関数がバッティングしていた

などの理由で試行錯誤回数が多くなってしまったのが原因か。

その他

出題者に「ステータス更新をわざと遅延させて、その間のステータス取得処理をキャッシュしてスコアを伸ばす」というはなしをしていて、 たしかにRESTなアプリケーションならそういうことをやるのに今回は全く思い当たらなかったなーと反省。

テストが用意されていたのにこれを有効活用できていなかった。 普段仕事しているときはテストを実行しないことなんてまず無いのに、 ISUCON=テストなんて無い という先入観でないがしろにしてしまった。 競技開始前にも「仕様が複雑なのでテストを用意しました」というアナウンスがあったというのに・・・。

最終計測でfailしてしまったのがとにかく残念。 確かに終盤のスコアが不安定だったので、直近の変更を2〜3revertしたにもかかわらず。 やりたいことが問題なくできていれば、20000点台には乗っていたはずなのだけど。

優勝したのは会社の同僚チームで、普段からGoでゲームのコードをバリバリ書いている人たちだったので、納得感はある。

今回も「普段やっていないことはできない」を実感する回だった。 悔しいのでまた出たい。

運営の皆様、参加者の皆様、ありがとうございました。