ISUCON9 予選
ISUCON9お疲れ様でした。
去年に引き続き「RE: ゼロから始めるISUCON」として1人チームで参加して来ましたが、無事16位に入ることができ、来月の本選に出場できることになりました。 3回目の挑戦で初本選ですね。ばんざーい ∩( ・ω・)∩
予選の感想
出題がSAKURA internetさんと、mercariさんということで、椅子を販売するサイトisucariでした。
「ベンチマーク」が「ベンチ」ジャンルに入っていたり、時間に追われながらもくすりとさせてもらいました。
ISUCON的にはRDBボトルネックから始まるものの、割とすぐに外部APIにボトルネックが移った印象。
結局API呼び出しをある程度減らしつつ、とにかくWorkerを増やすことでAPI結果待ちの間に他Workerが処理するようにしてスコアを稼いでいました。
感想部屋見ているといろいろ足りていなそうなので、怖いながらも講評が楽しみ。
使ったもの
最終的な構成
1台目:
- nginx(load balancer,
/upload
の画像配信) 1 - gunicorn (weight: 8)
2台目:
- gunicorn (weight: 10)
3台目:
- MySQL
- gunicorn (weight: 5)
やったこと
オーソドックスに計測・一番重い場所を改良の繰り返し。
items.root_category_idを追加
重いクエリの改善
categoriesテーブルをオンメモリに
親カテゴリ名まで含めて辞書定義
index追加
Slowクエリを元として、主にitems
にindexを追加
外部APIを出来るだけ呼ばずに済むように
この辺りで目立つSlowクエリが無くなって、API呼び出しが支配的に。
正直、これが正しかったのかはわからないですが、netdataで見ているとCPU使用率が0%と100%を行き来していたのでAPIのレスポンス待ちでworkerを使い切っているのかなー、と。
この時はcompaign
上げてなかったので、単純にベンチマーカーからリクエストが来ていなかったのかもしれません。
APIレスポンスの内容をJSONに含めて返す必要があったため、遅延処理もできず、workerをがっつり増やして対応。
改めて考えると裏でポーリングしておく手もあったかも?でもwait_shipping
以降の物が増えると破綻しそうだなぁ。
APIドキュメント読む→QRコードの実装に迷い込む
APPLICATION_SPEC.md
, EXTERNAL_SERVICE_SPEC.md
を読んで、Shipping statusがisucari側である程度把握できる(=APIレスポンスする必要が無いタイミングがある)ことを知る。
/accept
のタイミングがわかれば、大部分はわかるはず。でもこのURLは外部サービスのものだし……はっ!荷物を引き渡すときのQRコードを差し替えて、isucariを経由させれば……と実装。
1.5時間ぐらいかけて実装してみたものの、QRコードのvalidationに引っ掛かってしまってgit stash
orz
確かにレスポンスの変更にあたるからルール的に変更不可か……
3台構成に
アプリ側がうまく行かなくて凹んだのでインフラ側へ。
RDB負荷はある程度減らせていたようなので、DBサーバーにもgunicorn入れて数で勝負。
画像ファイルの配置がバラけてしまったのでNFSで無理やり共有。2
/upload
以下はnginxで提供。
結果
Job一覧を見ていると、こんな感じか。
- 13:45まで:色々手は入れているものの初期スコアのまま変化なし
- 14:00ぐらい: 3000点に上がって喜ぶ
- 14:20ぐらい: API関連弄って6000点
- 14:30ぐらい: worker数増やして9560点、一瞬だけ1位に
- 16:00ぐらい: QRコード系をあきらめてインフラ側へ
- 18:00ぐらい: ガチャが安定していたので数回走らせて12,960で終わり
最終スコアは12,960、最高スコアは13,560でした。
実はcampaignを上げるタイミングを逃し、後半で上げてみたら外部API呼び出しがエラりまくったので0のままです……(小声)