mesimasi Logo

isucon11予選に参加して本戦に滑り込んだ

isucon11予選に参加して本戦に滑り込んだ_thumbnail

今年も昨年と同じく さんぽし(@sanposhiho) さんと とさ(@tosa_now) さんと 「雑談係」としてISUCON11に参加してきました.(昨年は「雑用係」でした)

非常に楽しく,本当に運営の皆さんとチームメンバーには感謝するばかりです🙏

そしてなんとか学生枠最後に滑り込むことができ,本戦に出場できることになりました!🎉 isucon予選結果

5時になり,他のチームのスコアが凍結された状態では学生1位だったので思ったよりギリギリで焦りました..(ベストスコアは別チームが1位だったと思います) isucon5時時点のスコア

ちなみに分担は

  • @sanposhiho サーバー分割・メトリクス取得・インフラ周り
  • @tosa_now appの改善
  • @masibw(僕) DB・Index -> 終わったらapp でした.

やったこと

僕がやったことを時系列順に書いていきます.他のチームメンバーがやったことは各々ブログに書いてくれるはず… コードは githubに上がっています

開始すぐ マニュアル読み

チームメンバーで一緒にマニュアルを合わせ読みました. 画面共有をしながら,「ここのルールはbulk insertできそうだね」とか「これは気をつけないとね」みたいな話ができ,共通認識を持てたので良かったと思います.

10時20分くらい? git管理

コードや設定ファイルをgit管理できるようにしました. /webappいかでgit initをして必要なもの以外.gitignoreしてるんですが,他になにかいい方法有るんですかね(他のサーバーへ展開するときに重複するファイルを一旦消してからpullするのが少しめんどくさい)

10時30分くらい? indexを貼る

さんぽしさんにslow query log を出してもらい, pt-query-digest を使って分析してもらいました.その結果を使ってindexを貼りました.

isuテーブル

INDEX idx_jia_user_id (`jia_user_id`, `id`),
INDEX idx_chara (`character`),

isu_conditionテーブル

INDEX idx_jia_isu_uuid_timestamp (`jia_isu_uuid`, `timestamp`),

今回はあまりIndexを張れそうなクエリが出てこなかったのですぐ終わりました.特にisu_conditionテーブルに貼ったindexの効果が大きかったみたいで,ボトルネックが GET /api/isuから GET /api/trendへ変わったようです

11時30分すぎくらい? echo のログを消す

初期実装ではechoのdebugログが頻繁に出ていました.僕たちは使わなさそうだなってことでオフにしました.

	e.Debug = true
	e.Logger.SetLevel(log.DEBUG)

	e.Use(middleware.Logger())

これにより3000点くらいあがりましたが,正確性の高いチューニングを行うなら,どんなクエリがよく来ているのかなど分析したほうが良いと思うので,ココの力を更につけていきたいですね

12時くらいから getTrendの改善

お昼ごはんをつまみながら,ボトルネックになっていそうだった GET /api/trend の改善に取り組みました. 大まかに言うと「イスの性格ごとにコンディションを集計して返す」エンドポイントだったと思います. 最初は以下のような実装になっていました.

  1. 性格一覧を取ってくる
  2. For文を回して性格一覧と一致するイスを全件取ってくる
  3. 更にFor文を回してイスごとに最も新しいコンディションを取得する 2重For文の中でそれぞれDBにクエリを投げているので非常に効率が悪かったです.

結局の所使用されているのは「isu.id, isu.jia_isu_uuid, isu.character, isu_condition.condition, isu_condition.timestamp」だけだったのでこれらを一括取得しようと考えました. そこで次のようなクエリを書いたのですが,結局サブクエリをイスごとに回しており,マシではあるものの最良では無いように思えました.

select i.id, i.jia_isu_uuid, i.character, COALESCE((select isuc.condition from isu_condition as isuc where i.jia_isu_uuid = isuc.jia_isu_uuid order by timestamp desc limit 1), '')as `condition`, COALESCE((select isuc.timestamp from isu_condition as isuc where i.jia_isu_uuid = isuc.jia_isu_uuid order by timestamp desc limit 1), STR_TO_DATE('0001/01/01 00:00:00', '%Y/%m/%d %H:%i:%s'))as timestamp from isu as i order by timestamp desc

次のようなクエリも試したのですがあまり違いが見られませんでした.

select i.id, i.jia_isu_uuid, i.character, isuc.condition, isuc.timestamp from isu as i left join isu_condition as isuc on i.jia_isu_uuid = isuc.jia_isu_uuid  where isuc.timestamp = (select MAX(isuc2.timestamp) from isu_condition as isuc2 where i.jia_isu_uuid = isuc2.jia_isu_uuid limit 1) order by isuc.timestamp desc;

結局納得できるクエリを書くことはできなかったので,どなたか1発で取得できるクエリを書けた方は教えていただきたいです!

– 8/23追記 – こちらのブログを読んで知ったんですがMySQL8.0にはLATERAL句というものが追加されていたらしく,以下のようなクエリを用いることができそうでした. まぁMariaDBのまま使っていたのでこの構文が使えたのかは不明ですが…

select i.id, i.jia_isu_uuid, i.character, isuc.condition, isuc.timestamp from isu as i, LATERAL(select `condition`, timestamp from isu_condition as isuc where i.jia_isu_uuid = isuc.jia_isu_uuid order by timestamp desc limit 1) as isuc order by isuc.timestamp desc;

途中でappのfile descriptorが足りなくなったり,nginxのロードバランシングがうまく行かなくなってググったり相談していたとはいえこのエンドポイントに時間を書けすぎてしまったのが反省です…

3時30分くらい? 安定性を高める

スコアとしてはずっと上位にいて,きちんと試験に通れば予選突破できるのでは?という雰囲気になっていました.チームメンバーがbulk insertを POST /api/condition に導入してくれたのですが,たまに「順序が違います」というエラーで落ちるようになってしまったのでその原因を調べたりしていました.

結局なぜこのエラーが出るのかはわからず,予想としては「bulk insertしている時に次のbulk insertタイミングが来てバグってしまっている」か「DBとのコネクションがおかしくなって次以降のベンチで落ちる」みたいな感じかなぁってなりましたが,本当のところはわからずじまいです

とささんにbulk insert周りでmutexを取ったりしてもらいました.

5時過ぎ ポータルが止まる

そろそろ再起動試験をするか~と言っていたらポータルが落ちてしまいました.ベンチが投げれなかったのでマニュアルを読んだりアプリのコードを読み直してやばいところがないか確認していました.

6時 ポータル再開 & 再起動試験

再起動試験をして無事に動くことを確認しました.また,メモリが余っていたのでMariadbのconfigをいじってメモリ割り当てを増やしましたがあまり変わりませんでした.後はできるだけ触らないでおこうということで終了まで喋っていました.

最後に

今回のISUCONでは今までの経験や反省を生かして順調にスコアを伸ばすことができました.しかし,あまり多くの改善を加えることができなかったことや競技中にmacのハードディスクがいっぱいになり動作がおかしくなってしまったり(これは関係ないけど)と,まだまだ力をつけたい部分は多く見られました.

本戦に向けて,特に以下のことを練習しようと思います

  • 仕様を把握し改善を手早く行う
    • とくにSQLクエリの改善
  • どんなリクエストが来ているのかを分析することに慣れる

本戦まで1ヶ月弱しかありませんが,できるだけ勉強して優勝を目指したいと思います!!!!

タグ

Loading...

利用規約

copyright ©めしまし All Rights Reserved.