ISUCON 7 予選(1日目)に参加して悔しい思いをしてきました(アプリ編

こんにちは。 ISUCON 7 予選1日目に参加したわんこ。です
私自身は2年ぶり3回目の参加になります。 まずはOfficial(?)HAROiDチームの結果を御覧ください

チーム名: カリスマ

メンバー

結果

  • 最終提出スコア  111899
  • 競技中BESTスコア 113149
  • 予選参考順位26位(1日目だけだと8位
  • ダメでした

HAROiD でのISUCON対策

HAROiDでは、ISUCONの練習や参加は業務として扱ってもらうことが出来ました。 @muddydixon ありがとうございまっす。
チームメンバーは全員家庭持ちだったので、平日の練習、土日のリハーサル等が業務として扱っていただけたことで、かなり集中することができました。

他にも友人と参加していたりしていたメンバーも居たので、フェアに競うためにも練習用のリポジトリや、SlackなどはPrivateなものを利用していました。

Infra担当の @toritori0318 がInfra版のBlogを書いてくれているので私からはApp側から見た予選について書いていきます。

事前にやったこと

  • ISUCON6を各個人で一通りやってみる
  • 個人でやったことを集まってあーだこーだ言ってみる
  • 4時間(実際の半分の時間)でISUCON6を3人でやってみる
  • Pixivさんが用意してくれていた社内ISUCONの問題を使ってリハーサル
  • ISUCON5の問題も4時間でやってみる
  • 早起きの訓練

上記のタスクを2週間弱で敢行しました。 会社の会議室を使い、日曜日の9時半ごろに集合し、実際の寝起きの再現等をしながらリハーサルしていたのはよかったと思います。

疲れや、食事のタイミング、眠くて頭が回らない。等の自身のコンディションの確認をすることで、当日の予定をスムーズにたてることが出来ました。

事前準備

  • メンバーの公開鍵
  • GithubのPrivateリポジトリ
  • おやつと軽食の準備
  • VAPE(喫煙所が遠い)

当日やったこと(App)

  • /icons/* をファイルで書き出すように変更
  • デバッグ用のユーザーを追加
  • messageの未読カウントをRedisのソート済みセットで保持
  • havereadをredisのハッシュで保持するように変更

icons

iconsの画像ファイルは初期実装ではDBに保存されていたので、何も考えずに一度全てをファイルに書き出しました。
しかし、何度も同じファイルがuploadされることが確認できたので、ファイルが存在していればスキップするように変更(極力ioに負荷かけないように

実はこれがハマった原因だったな。と後で思い知りました。 画像が更新されないことにより、同じ画像ファイルを返しているつもりでも、ファイルの更新時刻が変わらずにベンチマーカー側が同じ画像と認識してくれず何度もfailしてしまいました。

users

次に、ブラウザで通信状態などを調べるためにユーザー登録をしていたのですが、ベンチマークを走らせるとinitializeで必ずDELETEされてしまいます。

おかげで複数ブラウザでチャットをして動作確認というのがとても面倒でした。そこで、/initializeの中を

-    db.MustExec("DELETE FROM user WHERE id > 1000")
+    db.MustExec("DELETE FROM user WHERE id > 1002")

このようにして、運営が用意していた1000User+デバッグ用2Userをいつでも保持できるようにしました。 思いの外、これは便利でした。

messageカウント

/fetchの中のSQLが支配的に高負荷なQuqeyだったので redisにme:{channelID}のKeyでMember,Score共にMessageIDのソート済みセットを作りました。 これは初期データ数が少なかったことも幸いし、/initializeの中ですべてredisに格納することができました。

はじめredisのZCOUNTで未読件数を計算させていましたが、 O(log(N))+O(M)の計算量になってしまうので、途中でZREVRANKに変更しました。そうすることで、O(log(N))の計算量だけで済むようになりました。スコアは少しだけ上がったくらいでしたが・・・。 これはScoreの値がIDというユニーク保証されていた値だからできた実装でした。

haveread

havereadのテーブルもかなり高負荷なQueryだったのでredisのハッシュ型で保持することにより、MySQLのCPU負荷を大幅に下げることが出来ました。

反省点

本当は上記に書いたこと以外にもたくさん試行錯誤してみたのですが、failしてしまったり別の問題が発生してしまったりしてしまいました。

Infra1人、App2人と完全にわけてしまっていたので、今回のような問題ではInfraとAppの両方から考えて対策できる配置がよかったのかな。と思いました。

ISUCONでは良く言われていることですが 普段やってないことはISUCONでは出来ない この言葉が身にしみましたね。
HAROiDでは普段超高負荷なAPIサーバーの構築がメインになっており、静的コンテンツ配信におけるノウハウは知識レベルに留まってしまい、習得できていないことが浮き彫りになってしまいました。

ここ抜けれてたらApp側の戦いになっていたと思うのでとっても悔しいです。

来年はどんな問題になるかも予想すら出来ませんが、また挑戦するのでそれまでにはインフラ力身につけたいと思いました。

謝辞

今回は予選では初の複数台構成でした。 私が唯一本戦に残れたISUCON4の動画配信を思い出す問題でした。

予選からこのクオリティの問題を提供してくださった昨年の優勝チームの皆さん、参考言語を実装してくださった方、サーバーリソースを提供してくださったさくらクラウドさん、運営のみなさん、予選を楽しい戦いにしてくださった参加者のみなさんありがとうございました。

さいごに

HAROiDではLiVE CMといった1分間の超高負荷に耐えるプロダクトの開発も行っております。1分、超高負荷、チューニングということでビジネスISUCONと社内では呼んでおります(たぶん)

そういった環境で一緒に開発をしてくれるメンバーを募集しております。 興味を持っていただければ、遊びに来ていただいたり、お話したりだけでも大歓迎ですので是非よろしくお願いいたします。

HAROiD - Wantedly