終電23時11分って早くね?

都内のIT企業で働くカラオケ大好きエンジニアの雑記

ISUCON13に参加してスコアなしでフィニッシュしました

こんにちは。株式会社リンケージに所属しております、青ごへいもちです。

ISUCON13に参加しまして、残念ながらスコアなしでのフィニッシュとなりまして、その共有になります。。

という悲しいミスでした…。

ギリギリまでなんとかしようとして余裕がなかったのと、ちゃんとログをオフにする系の素振りをすべきでした…! そして、最高スコアも7000点くらいなのでなにをそんなにあせることがあったの?と言われてもしょうがないくらいのアレです。

また、この記事は 株式会社リンケージ Advent Calendar 2023 14日目です!

ISUCONとは??

isucon.net

ISUCONとはLINEヤフー株式会社が運営窓口となって開催している、お題となるWebサービスを決められたレギュレーションの中で限界まで高速化を図るチューニングバトルです

Iikanjini Speed Up Contestを略してISUCONです!

ISUCON13

isucon.net

2023/11/25(土)に開催されたISUCON13。 ISUCON13のお題は「ISUPipe」というライブ動画配信サイトでした!

www.youtube.com

出題動画!かわよい!!

ということで本記事ではISUCON13に参加したログを残しておきたく書いております。

事前準備

今回は初動の動きを固めるべく、初動のみの素振りを重点的に多分10〜20回くらいやりました。

  • 各サーバーへの初期設定の投入
  • GitHubへのバックアップ
  • PHPの実装への切り替え

「対象サーバーのIPが分かったら/etc/hostsを書き換える」というようなところまでタスク化。 各サーバーへの初期設定はAnsibleで実施しました。

NaruseJunチームのリポジトリをめっちゃ参考にさせていただきました。

Ansible専用のリポジトリを用意して make isucon を実行すれば各サーバーの設定がされるという感じにしました。

この実行がまぁまぁ時間かかるので並行で、

  • サーバー環境の確認
    • サーバースペック、ホームディレクトリの確認、想定しているところに設定ファイルがあるか?などを確認
  • バックアップの実施
    • アプリケーション、設定ファイルのバックアップ
  • PHP実装への切り替え準備
    • 当日マニュアルをみて、切り替え方法を確認など

をするようにしていた。

PHP実装の切り替え時には、NGINXのログの設定、MySQLのスローログの設定も済ませておく流れ。

で、PHP実装でベンチマークを実行。

というところまでをひたすら素振りとしては繰り返して練習しました。

また、過去問の素振り自体はISUCON11の予選の問題を本選出場相当の点数が出るところまでコツコツやったりなどしていました。

speakerdeck.com

PHPerTeaNightでuzullaさんがお話ししてくれたスライドもめっちゃ見返して、手順に取り入れたりもしました!!

当日やったこと

はじまる前

初動

初動は練習の甲斐あってかなかなかスムーズに進みました。 他のメンバーにマニュアル読みなどを任せて、素振り通りに対応。

Goの初期スコア

Goの初期スコア

PHPの初期スコア

PHPの初期スコア

一応、10時37分32秒にPHP実装での初回ベンチを回せていたようです。

1,000点位差がありますが、この時点でスローログなど出していると思うのでそんなもんかなーと思います。

pt-query-digestの結果をもとに色々貼ってもらって。11時42分時点では30位前半のスコア(7,236)が出ていて「いけるのでは?」という雰囲気だったのがハイライト。

ベンチマーカーの履歴

その後

初動以外はほぼいいところがなかった!!!!!!!!!!!!!!!!くやしい!!!!!!!!!!!!!!!!!!!!

  • 引き続き、pt-query-digestの結果を元に
    • インデックスの追加
    • N+1の解消
      • 1発で解消できないことが多くて手戻りがまぁまぁあった…
  • iconのハッシュ値計算
  • tagをDB参照しないように
  • isupipeのDBを分離
  • isudnsのDBを分離

をなんとなくやっていました。

DNSについては、メンバー1人に大きい時間を割いてもらってみてもらっていたのですが、思うような改善を回すことができず…

最後にログ系を切ってベンチ回して終わりにしましょうと17:50くらいになって対応したのですが、冒頭にも書いた、xhprof用の読み込みをコードから削除するのを忘れてしまいFailでフィニッシュという結果でした。。

感想戦

悔しすぎたので感想戦をコツコツやっていました。 それぞれやったことによるスコアなどはメモってなかったので割愛です…🙏

インデックスを貼るDBの調整

当日、データベースにインデックスを貼っていたのですが、よくよく確認してみるとうまくはれてなさそう?ということに気がつきました。 原因としては、isupipeのDBを分離した際、初期化時にインデックスを貼る処理が実行されないことを見落としていたことによるものでした。。

github.com

こちらに追加してた。

iconのハッシュの処理

これも実はうまくできていませんでした。 ISUCON13 問題の解説と講評の中にもあるように、

If-None-Matchは前後に " がついているので、削除するか文字列が含むかを調べることができる関数、メソッドを利用するとよさそうです。

のところが原因でした…

N+1の解消

今回の問題は過去のISUCONの中でもN+1が多かった問題だったような気がしているのですが、解消できていないN+1の箇所がまだまだ残っていました。

  • JOINによる対応
  • 複雑なクエリの分解
  • 単純なクエリに対するキャッシュの利用

などを実施し、pt-query-digestの結果を見ながら1つ1つ潰して行きました。

このN+1は地道にやっていくことでスコアが伸びていったので、やはりとても大事でした。。

が、何度も間違えながら解消を繰り返しまして、当日、なるべくミスのないように素早く解消するためには過去問の素振りなどをもっとやる必要があるな…と感じます。。

ランキングの算出部分なんかは特に複雑で、正しく仕様を読み取り、正しく直す…というのが必要で難しかった…

iconハッシュのキャッシュ

N+1の解消の中にも含まれるのですが、iconのハッシュをキャッシュしました。

アイコンの取得、アイコンの更新のリクエストを同じサーバーに向けてAPCuを利用してキャッシュする方法をしました。

その他、同じアイコンの取得・アイコンの更新と同じサーバーにAPIリクエストを向けられないものは、1秒でキャッシュが切れるような設定でキャッシュするなどしました。

この辺りiconの参照リクエストが多いので大きく効いていた気がします。

preloadの設定を有効にする

これめっちゃ効きました。

これもuzullaさんの記事を参考に設定。PHP-FPMの起動時に対象としたファイルがpreloadされるのですがなかなか点数が伸びたのでPHPer必須スキルかもです。

PHP-FPMを再起動しないとファイルの更新が反映されないと思うので忘れずにサービスの再起動をしましょう。

処理の分散

サーバ1: NGINX, PHP-FPM サーバ2: PHP-FPM, DB(isupipe) サーバ3: DB(isudns)

のようにサーバの役割を分離。

サーバー2のCPUに空きができていたので、NGINXでアクセスをサーバー1とサーバー2に振り分けるなどしました。

N+1を解消すると負荷状況が変わったりしたので、ちまちま振り分け設定を調整したりしました。

registerHandler、searchLivestreamsHandler(の全件検索)でusleep

ベンチを数回実施&alpでのアクセス数を見るに、

  • [GET] /api/livestream/search: ちょっと少ない
  • [POST] /api/register: ちょっと少ない
  • [GET] /api/livestream/{livestream_id}/livecomment: 多い

の時にスコアが上がる(スコア計算的にも投げ銭が関与するのでというところだと思う)ので、いい感じにsleepをいれたら結構効果がありました。が、xhprof見づらくなるので実施するタイミングが難しい。

みたいなことをやっていました。

ここまでで、7位相当くらいのスコアになりました。(c2.2xlargeのインスタンスベンチマークを実施)

7位相当のスコアに到達

感想戦にはISUNARABEを利用させていただきまして、とても便利で感謝しかありません!!!!!!!!!!!! この場を借りまして、お礼を申し上げます ✨🙏✨🙏✨🙏

ISUCON当日のインスタンスを起動したり停止したりしながら、ISUNARABEでベンチマーカーを実行して…みたいにコツコツやっていたのですがとても便利でした。

だいぶ時間を溶かしたので打ち止めとしたのですが、その時のxhprofの結果はこんな感じでした。 (usleepはなしにした状態)

サーバ1: NGINX, PHP-FPM

サーバ2: PHP-FPM, DB(isupipe)

PDO::__construct が大きいボリュームを占めるのが分かります。

「これはPHPerKaigiでみたやつだ…」となってRoadRunnerの導入を試したのですが、うまくいかず断念。

Cookie周りの処理でエラーになってしまっていたのですが、ちょっと時間がなくて解消し切れなかったのでどこかでチャレンジしたいです。

ただ、まぁここまで本番中にたどり着くのか…????みたいな問題はあるので、基礎をもっとがんばらねば…というところですね。。。

あとは json_encode が遅かったりしてたのですが、解消方法が分からなかったな…

NGINXでのアクセスの振り分けもいつも悩んでしまうので悩まないようにしたい。。

来年にむけて

いろいろと反省点はありますが、、、、、、

  • 初動の練度をもうちょっとあげる
    • もうちょっと速くできそうなので…!!
  • DNS!?」みたいに驚きすぎないで地道な改善に重点を置く
  • コードの改善(N+1)などを速く、的確に対応できるようにする
    • これは手を動かした回数では?となっているので素振りをがんばる

みたいなところは頑張りたい…! そしてめざせ30位以内。

まとめ

ということで、ISUCON13に参加しました!とても楽しかったです!!(&悔しかったです!)

運営のみなさま、ありがとうございました!!!

来年も開催されましたら、来年も個人スポンサーをして、出場枠をゲットして、PHPでなんとか爪痕を残したいなと思っています!!!!

以上です!!!