ISUCON14に参加して23位になりました (28156点)

去年の isucon13 に引き続き、overcached で ISUCON14 も参加してきました。私は今年で 2 回目の参加です。 結果は 28156 点で 23 位でした。目標としていた入賞 30 位以内を達成できて嬉しいです。 チームメンバーはもやしなーです。

サーバー構成は、app, db, matching 全部入りの一台構成でした。

やったこと

9 時過ぎくらいから予約していた貸し会議室に集まりました。競技開始後はデプロイや計測準備、レギュレーション読みやアプリを触って仕様を確認するなどを各々分担して行いました。 11 時前に一度分担していた部分の情報共有と作戦を練ってから改善に取り掛かりました。 当日は以下の改善を行っています。

[4119] INDEX 貼る, interpolateParms=tureを設定する

slowquerylog を見ながら chair, chair_location, ride_status, ride, coupone のテーブルにインデックスを貼りました。

[5044] ownerGetChairs の chair を IN 句で取得

総走行距離を取得する部分を椅子ごとにクエリ実行していた部分を IN 句に置き換えました。

[8658] notification の RetryAfterMs を減らす

30ms で client にリトライさせていた部分を 1000ms ごとに変更しました。rides のテーブルがない場合のみ 200ms でリトライするようにしました。 値についてはアプリを触ったところ体感 1s ごとに椅子が移動しているように見えたからだそうです。

[25518] マッチング改善

空いている椅子の数だけ古い順にマッチングリクエストを取得した後、マッチングリクエストをユーザーの現在地から目的地の距離が長い順に並び替えてから、近くの椅子を順に割り当てていくロジックにしました。 ログを出したところマッチングリクエストがめっちゃ余っている!というのに気づけたのですが、これに気づいたのは午後を回ってからでした。

負荷を見ているだけだと初期実装だと大して負荷をかけているところではないので、なかなか気づけなさそうです。 ベンチマーカーのログを丁寧に見れば気づけたのかもしれません。 私達のチームは、そろそろマッチングシステム見てみようか〜とコードを読んでみたところでヒントとなるコメントを発見しました。 これは改善しないといけないやつ…!

// MEMO: 一旦最も待たせているリクエストに適当な空いている椅子マッチさせる実装とする。おそらくもっといい方法があるはず…

[28156] ride_status のメモリキャッシュ

rides_status の status を In memory でキャッシュしています。 read-throgh のキャッシュ戦略と更新時にキャッシュを更新するように実装しています。 いつもは更新時にキャッシュを delete しているだけで問題なかったのですが、ベンチの WARNING が発生してしまうのでキャッシュをちゃんと更新してあげるようにしています。

できなかったこと

複数台構成

やってみたところスコアに貢献できなかったので、main にいれませんでした。 実際にはマッチングサービスの停止を忘れていたので、3 台ともマッチングサーバーが起動した状態になっていたのがスコアが改善しない原因でした。 upsolve でマッチングサーバーを停止して再度 DB を別インスタンスにしたところ 33319 点までスコアが上がりました。 勿体ない…

走行距離の事前計算

座標更新の際に総走行距離を計算して DB に持っておく実装をしたのですがスコアに貢献できなかったので main にいれませんでした。 座標更新の API が数 ms 遅くなってしまっていたのがスコアに貢献しなかった原因だと思います。最終的には総走行距離を計算するクエリが slowquerylog のトップを専有するようになっていたので、次の課題になると思います。

memcached によるキャッシュ

rides や ride_status を memcached に入れて DB へのリクエスト数を減らそうとしたのですが、ベンチマーカーの WARNING を取り除くことができませんでした。 普段は read-through のキャッシュと更新時に cache の delete をしているのですが、Notification と Coordinate の両方が高頻度で呼ばれているので更新時にキャッシュを消しても古い値でキャッシュを上書きしてしまっているのかもしれません。 唯一入れられたキャッシュは ride_status に対するキャッシュで、これは memcacehd ではなく dictionaly でキャッシュしていました。

本番で慣れていない dictionaly でのキャッシュを行ったので, initialize 時に実はキャッシュ削除できてません。競技終了後に気づいて、「やべ…」って呆然としてましたが、ラッキーで再起動試験をパスしていました。

SSE (Server-Sent Events) 実装

「ChatGPT のやつじゃん」と盛り上がりつつ、時間切れで実装までたどり着くことはできませんでした。

感想

8 月から月 1 ペースで、貸し会議室やメンバーの家で過去問練習をしていました。毎回ちょっとした旅行気分で楽しかった分、ISUCON が終わった今少しさびしい気持ちもあります。

本番は走行距離の事前計算やキャッシュの部分の実装を行ったもののなかなかスコアに結びつかなかったり、ベンチマーカーの WARNING が取れなかったりと個人的には大苦戦しました。 30 位以内という目標達成の喜びもある一方で, 実際に自分の改善でスコアに結びついたのはインデックスを貼った部分くらいなので、もっとスコアに結びつく改善をしたかったなと少し不完全燃焼です。 しっかり upsolve しようと思います。

来年はトレーシングにも挑戦してモニタリング力も向上させていきたいです。

comments powered by Disqus