2015-09-29

[isucon] ISUCON5 予選敗退しました

ISUCON5 予選に土曜日の日程で参加しました。チーム名は円山町、チームメンバーは @ymz_kotaro と2人です。主にアプリの改良を担当しました。午後6時半ごろのスコアは12000点ほどで予選敗退しました。

予選当日の流れは大体こんな感じでした。

午前11時~午後2時
何もいじらずにベンチマーク実行、タイムアウトでFAIL。
my.cnf の設定すべき個所に右往左往しながら innodb_buffer_pool = 1G を設定してようやくベンチマーク通過。
GoAccess で nginx のアクセスログを解析してアプリ宛にしかリクエスト来てないと判断し、nginx の設定は放置することとする。
Ruby 実装のまま MySQL にスロークエリログ 0.1 秒を仕込んで pt-query-digest 見る、インデックスなしのクエリを発見したのでひとまずインデックスを修正。
Go 実装に systemd の設定を切り替えてテスト、ベンチマークはエラー多数で FAIL。
エラー原因を目視確認しようとするが見つけられず。試しに一度 go build -o app を実行して再起動すると動くことを発見。
3回連続でベンチマーク正常を確認したのでGo実装を使うこととする。

午後2時~午後7時
Go実装のアプリにデバッグ用サーバー net/http/pprof を組み込んで再起動する。ベンチマークを流しながら go tool pprof で CPU プロファイルを取得し、top50 -cum で関数プロファイル、list GetIndex で行プロファイルを取得して遅い部分を解析
プロファイル上時間がかかっているように見える N+1 クエリを修正。
users テーブルへの書き込みがないので初期化時に全体をロードするいんちきオンメモリ化を施す。
全て修正完了したと思っていた N+1クエリについて、テンプレート関数経由でデータベースアクセスしている部分を発見したので修正。
テンプレートエンジンを高速化しようと試行錯誤するがいまいち早くならず終了。

午後7時時点でやり残したと思っていた点
html/template の使い方でリクエストごとにテンプレートを解析していたので何とかする
gorilla/muxjulienschmidt/httprouter に交換

翌日の反省点
クエリごとに毎回 relations テーブルと JOIN せずに、友達一覧を先にとって、各クエリで再利用したほうが有効なことが GoBoldチームさんのコード を見て気づく
ローカルストレージ遅いと聞いてからデータの安全性を犠牲にする感じの MySQL の設定を試していなかったことに気付く

リンク
ISUCON公式Blog
hidekiy/isucon5q - app.go