こんにちは。株式会社リンケージに所属しております、青ごへいもちです。
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回くらいやりました。
「対象サーバーのIPが分かったら/etc/hostsを書き換える」というようなところまでタスク化。
各サーバーへの初期設定はAnsibleで実施しました。
NaruseJunチームのリポジトリ をめっちゃ参考にさせていただきました。
Ansible専用のリポジトリ を用意して make isucon を実行すれば各サーバーの設定がされるという感じにしました。
この実行がまぁまぁ時間かかるので並行で、
サーバー環境の確認
サーバースペック、ホームディレクト リの確認、想定しているところに設定ファイルがあるか?などを確認
バックアップの実施
PHP 実装への切り替え準備
をするようにしていた。
PHP 実装の切り替え時には、NGINXのログの設定、MySQL のスローログの設定も済ませておく流れ。
で、PHP 実装でベンチマーク を実行。
というところまでをひたすら素振りとしては繰り返して練習しました。
また、過去問の素振り自体はISUCON11の予選の問題を本選出場相当の点数が出るところまでコツコツやったりなどしていました。
speakerdeck.com
PHPerTeaNightでuzullaさんがお話ししてくれたスライドもめっちゃ見返して、手順に取り入れたりもしました!!
当日やったこと
はじまる前
初動
初動は練習の甲斐あってかなかなかスムーズに進みました。
他のメンバーにマニュアル読みなどを任せて、素振り通りに対応。
Goの初期スコア
Goの初期スコア
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 でなんとか爪痕を残したいなと思っています!!!!
以上です!!!