limitusus’s diary

主に技術のことを書きます

ISUCON5 予選通過してきた

9/26,9/27で開催されたISUCON5の予選に9/27分で参加して通過してきました。

3人チームで出場しましたが、自分の視点での時系列でまとめておこうと思います。
(書いてある内容は自分の作業だけではありません)

概要

spec: n1-highcpu-4 (4vCPU, 3.5GB RAM) 1台

時系列

10:00
  • 競技開始。事前に準備していたレポジトリをcloneしてきてセットアップを開始。
  • 8/26時点でUbuntuと公開されていたことには全く気付かずCentOSを想定しており面喰らう。
  • とりあえず初期ベンチ。220くらい(記録忘れた)
  • インフラ担当として各種パッケージを放り込む。
  • tmux, openrestyはソースからビルド。nginxは結果的に1.6とか入っていたので何も考えずにビルドして問題なかった
  • 練習のときは全く触れなかったsystemdでアプリが起動している
    • 慣れた手順にするためsupervisordをインストー
    • nginx→openrestyについでに切り替え
    • memcachedも立てておく
    • ruby実装をsupervisord経由の起動に切り替え
      • staticなものはさっさとnginxで返す
      • ベンチがContent-Lengthを要求しているがnginxがgzip圧縮していてContent-Lengthがつかない
      • しょうがないのでgzipはoff
  • mysqlがAppArmorでハマる
    • 1時間くらい悩んだ
  • slowlogが全クエリ出るようになった
  • nginxのアクセスログ解析もできるようになった
12:00
  • 少しコードも見始める
  • entries.bodyをsplitして1行目をtitleに使う作りに見覚えを感じる
    • titleカラムを足して切り離す戦略を取り始める
  • 他にもいくつか飛んでいるクエリを見てindexを追加しようと試みる
  • buffer pool sizeが128MBな一方データが2GBほどあることに気付き愕然とする
    • あわててbuffer pool sizeを変えるが反映されずハマる
  • 50万行のentriesテーブルにindexを貼ってカラム追加するのに20分弱かかった
  • この時点で / へのアクセスが遅いことには気付きつつ、中でいろいろやっているのでいったん後回し。
    • 簡単そうなやつから着手している
  • エントリについたコメントの件数をSELECT COUNTしているのが気に入らなかったのでnum_commentsカラムを追加して更新するようにする

このあたりmysqlの設定変更に手間取りなかなかベンチマーク走行ができず焦る

15:00
  • ようやくALTERが実行でき、entries.bodyからtitleを切り離す作業が完了
  • スコアが2500あたりになる
  • footprintsのクエリが激重なので戦略を考え始める
    • 日付ごとに最新の訪問記録しかいらない
    • 最新のだけ持つことでGROUP BYを消去すればいい
  • 裏では「DOM要素 '#friends dd.friend-friend a' に文字列 'タマキ' をもつものは表示されないはずですが、表示されています」というエラーに苦しんでいるようだ
    • 確率的に失敗しているのか、再現条件がよくわからず一旦スルーする
  • それまで0.35secほどかかっていたfootprints系の処理が0.01secにおさまる。
  • やはり / に0.4secかかっておりここに着手
    • 基本的にはキャッシュ戦略に注力することになる
  • たしかこの辺でスコア3000に到達するチームが現れたと思う
16:20
  • mysqlslowdumpでこの辺のクエリに目をつける
Count: 611848  Time=0.00s (32s)  Lock=0.00s (27s)  Rows=1.0 (611848), root[root]@localhost
  SELECT COUNT(N) AS cnt FROM relations WHERE one = 'S' AND another = 'S'

Count: 500  Time=0.03s (16s)  Lock=0.00s (0s)  Rows=1000.0 (500000), root[root]@localhost
  SELECT * FROM entries ORDER BY created_at DESC LIMIT N
  • 1つ目は最新のエントリを表示するためのものなので、entriesとrelationsをjoinしたクエリを投げるようにすることで解消
17:00
  • このあたりで汎用キャッシュ機構が完成し、ベンチマークが再び流せるようになる
  • スコア20746
    • その前のスコアが2000点台だったので一気に順位が2位に上昇
17:10
  • 最新コメント10件のエントリ情報を出す部分を考え始める
    • publicとprivateでそれぞれ10件取得してUNIONしてORDER BY, LIMITすれば同じものが取れる
    • さらにindexを追加
17:30
  • 安全のため再起動試験を行う
    • supervisordが起動するようになってなかった…修正
    • 他は全て問題なし
    • InnoDB data fileをキャッシュに乗せないとキツそう?ということで初期化処理に追加
17:37
  • ひととおりやろうとしていた改善が完了し、スコア22230
  • 何度かベンチを回しつつ、他チームに追い付かれないかヒヤヒヤしながら待つ
    • なお最終スコアでなく最高スコアで順位がつくとみんなで勘違いしてた
18:00
  • 終了し解散。

結果

http://isucon.net/archives/45532743.html

2日目の4位(スコア20162)に入ったということで本戦出場が決定しました。

本戦は猛者だらけなので勝てるか怪しいですが頑張ります。