- 2018/10/10 水曜日 21:05:09
- ISUCON
毎年でているISUCONに今年も山形組として参加してきました。
結果は総合15位ということで、ギリギリでしたが予選通過しました。第1回からずっと同じ2人チームで参加していて、本戦出場回数は6回(1, 2, 3, 4, 6, 8)になったみたいです。そろそろ本戦優勝したいです。
やったこと
- 事前準備は空レポジトリ作成と、情報共有と秘伝のタレのコピペ用のスプレッドシートの作成など
- 選んだ言語はもちろんPerl
- そろそろGoで挑戦しますか?というのを3年ぐらい言い続けて未着手
- 普段の仕事はPerlなので手に馴染んだ道具を使うということでいいと思っている
- 最初のおきまりの作業
- 初回ベンチ
- 初期コードのレポジトリコミット
- デプロイスクリプト用意
- アプリの挙動確認
- コードリーディング
- 作戦会議
- ここまでで2時間ほど
- 作戦会議
- 「あー、これはISUCON2再来な問題ですねぇ。」
- そのISUCON2のときに我々はアプリケーションを全部書き換えて、データをメモリにすべて乗せるという戦略をとって、2位という結果を残していた
- けど、ISUCON5の予選で惨敗してからはその戦略をきっぱりやめているので、今回も普通のチューニングを進めていくことに
- 予約情報のデータ量が多いので、高速化が進むと途中からデータストアプロセス(初期はMariaDB)のメモリに全データが乗らなくなるという、ISUCON2の我々の戦略に対するカウンターなのでは?という予測をたてる
- イベントIDで接続先DBを決定して、 3台または2台のDBで水平分散というのが最終形かなぁ(結局準備はすすめたけどやらず)
- というのを意識しつつ直近のボトルネックを改修していきましょうというスタート
- 「あー、これはISUCON2再来な問題ですねぇ。」
- ISUCON7のときのCache-Control: publicやISUCON4のときのCache-Control/Expiresの悔しい思いがあるのでキャッシュ関連を調査
- HTTPのreq/resヘッダーを未知のものも含め全てログ保存する自作のPSGI middlewareを用意して、ベンチ中の全ヘッダーをみれるように
- 同じことをやるmiddlewareがないので整理して公開してもよいかも
- 各種キャッシュ関連のレスポンスヘッダをいろいろと付与して、appにくるアクセスでは条件付きリクエストの類はまったく行われないことを確認
- HTTPのreq/resヘッダーを未知のものも含め全てログ保存する自作のPSGI middlewareを用意して、ベンチ中の全ヘッダーをみれるように
- 実際に行った改修
- 12:52 sheetsテーブルのインメモリ化
- 13:41 h2o -> nginx
- 14:14 座席の詳細いらないときにも内部的にはとってきているのを省略
- 15:22 残席数の取得を1SQLに。こういうSQL各所に書いた。
SELECT e.*, count(case when r.sheet_id between 1 and 50 then 1 else null end) as reserved_S, count(case when r.sheet_id between 51 and 200 then 1 else null end) as reserved_A, count(case when r.sheet_id between 201 and 500 then 1 else null end) as reserved_B, count(case when r.sheet_id between 501 and 10000 then 1 else null end) as reserved_C FROM events e left join reservations r on (r.event_id=e.id and r.canceled_at is null) WHERE e.id = ? group by e.id
- 15:43
where public_fg=1
をPerlでやっているのをSQL化 - 15:43 reservationsにindex追加
KEY `event_id_and_sheet_id_idx` (`event_id`,`sheet_id`), KEY `event_id_cancel` (`event_id`,`canceled_at`)
- 16:05 get_event内でreservationsに全シート分の1000回クエリなげてるところを1回に
- この時点でスコアは 18,992 でベストスコアで3-4位あたり
- 16:13 isu1のオールインワン構成から isu1-web/app isu3-dbに(isu2はこのあと最後まで遊ばせることに…
- 16:55 いくつかのFOR UPDATE消し/ IFNULL(canceled_a, reserved_at)をmodified_at化
- 17:00 他チームのスコアが非公開になるタイミングで、スコア: 44,450でベストスコア2位で折り返し
- 17:24ごろ get_login_userの呼び出し抑制、FOR UPDATEの削除
- このあたりで、ベストスコアの 57,093
- event_sheetsテーブルを新設して、予約を
UPDATE event_sheets set reserved=1, hash=? where event_id=? and rank = ? and reserved=0 order by rand() limit 1
というSQLでやるというのをいれたけどスコアが下がり取り下げ - ~18:00 取り下げたけどその後スコアが安定せず、実行するたびに2万台~3万台をうろうろ
- 最終スコアをなんとか 39,677 にもっていき終了
感想
最後スコアが安定しなかったのは、FOR UPDATE消したことも影響しトランザクションにミスがあったことが原因だというのは感想戦でわかりました。なので正直最後は運もあったなぁという感じはしています。
感想戦ではその後
– isu1-web/app isu2-app isu3-db の3台構成に
– event_sheetsの件を再投入
– 適切なトランザクション
で10万点までとれました。
予選での複数台構成、コードのボリューム、ベンチの快適さ、運営全体のストレスのなさ、すばらしい予選になっていたと思います。(通過したからというバイアスもありますが)
karupaneruraさんをはじめ出題担当されたDeNAの方々、カヤックさんはじめ協力されていた方々、LINEの運営を担当されている方々には感謝です。
ということで、何はともあれ、本戦にまた参加できることになり嬉しいです。
今度こそ優勝だ!
コメント:0
トラックバック:0
- この記事のトラックバック URL
- https://blog.everqueue.com/chiba/2018/10/10/846/trackback/
- トラックバックの送信元リスト
- #isucon 8 予選15位で通過しました - へぼい日記 より