ちゃっくのメモ帳

ちゃっくがメモしときたいことをメモしとくよ

ISUCON9の予選を敗退したっぽい

ISUCON9の予選にチームIQ1で参加しました。
チームのメンバーは僕(学生)、yaketake(社会)、zakuro(社会)でした。

予選から少し時間が経ってしまったので記憶が薄れかけているので、怪しい記述が多いですが、一応参加期を書きます。

朝9時半
集合。3人とも開始前に揃うことに成功した。

競技開始。とりあえずインスタンスの起動。
一応ここで詰まると辛いので,他の2人の監視のもとで建てる。
インスタンスの起動は事前に一通りやっていて良かった。ただ、ISUCON Discord見るとなんか免許証とか求められてる人がいるらしくてAlibabaに免許証提出するの嫌だなぁとか不安だったから問題なくインスタンスを建てれてよかった。
とりあえずチームIQ1の方針は複数台構成は競技終了1時間くらいでやろうねくらいの雰囲気だったのでとりあえずインスタンスは1台立てた。

インスタンスが起動したらとりあえずpythonに切り替えてベンチマークを走らせ,アプリケーションの把握。
この時点で確か1400点くらい。
今回のアプリISUCARIを開く。
とりあえずアプリはメルカリっぽいなにか。
ログインすると大量の画像が目に入ってくるので,とりあえずこの画像をnginxで静的に配信することにした。
これをやってる間にyaketakeさんはローカルでアプリが動くようにしていて、zakuroさんはソースコードを読んでいた。

nginxで静的に画像を配信してベンチマークを走らせるが点数は上がらない。
これは多分別に画像をDBに入れてるわけではなくflaskが配信してくれているのでそんなにコストは大きくなかったのだと思う。

次にとりあえず典型のN+1の解消をすることにする。zakuroさんはどこにN+1があるのかわかっているっぽかった。
zakuroさんとそれぞれどこのN+1を解消するか相談する。
数分返事がないと思ったら明らかなN+1を全部解消していた。(早すぎてビビった)
確かこの時点で点数が3500点くらい?

試しにcache-controlを設定したが、点数は上がらないのでcache-controlはとりあえず外すことにする。
nginxのworkerとmysqlのworkerを増やすが点数は上がらず。

このあたりでyaketakeさんがAPIが連続で呼び出されているところを見つける。
yaketakeさんはAPIコールを減らせないかとかAPIの使用を調べ始める。

(ここらから割と何していたか記憶がないので時系列ぐちゃぐちゃ)
slow queryを設定。すこしコストの大きいクエリはあるがこれ以上最適化できなかったり、アプリのパフォーマンスに対してクエリ処理のコストが低かったりで、とりあえず後回し。
ソースコードの@lru_cacheが気になる。これ、分散させたときに不整合の原因になりそうだから外したい。外してベンチマーク走らせてもそんなに影響がなさそう。
zakuroさんがなにかして5000点くらいまであがる(何をしてたか記憶がない)。
複数回ベンチマークを走らせるとfailしまくる。
「俺、またなにかやっちゃいました?」
DBがRedisに載せられそうという意見がでる。僕はそもそもDBがボトルネックになってる雰囲気がないのであんまり効果がないと予想して反対。
dstatを見ても別にCPUがネットワークの問題でもなさそうで分散すればいいというわけでもなさそう。
割と何をすればいいかわからなくなってきたので、プロファイラを動かした。
PythonのLineプロファイラを動かすとAPIの呼び出しがボトルネックになってることがわかった。同じ場所にN+1が紛れていたが、API呼び出しのコストが大きすぎてN+1の影響があんまり大きくないのでAPIをやっぱどうにかしたいという判断。
APIをまとめて呼び出せないかと思ったけど無理そう。とりあえず非同期にAPIを呼び出せばいいということで総意がとれる。
Pythonで非同期処理はasyncioを使えばいいらしいが、誰も使ったことがなくてここで戸惑う。
みんなで「Goにすればよかった...」って言い出す。
残り30分くらいでFailしない感じになったが残り15分くらいでgitがぶっ壊れる(え....)
というか、分散化に乗り出すのがおそすぎて分散させる時間が残っていない。
gitが壊れた結果、アプリケーションが動かなくなって焦る。
僕は別に分散用に用意しておいたインスタンスを分散用ではなくバックアップ用として動くようにする。
gitを直して残り数分でベンチを動かすとFailする。
このあたりでjobがリジェクトされたりしていたので、負荷が大きすぎてAPIの呼び出しに時間がかかりすぎてFail判定になっているのではないかと話すがどうしようもないのでクリックしまくってjobをなんとか投げるがFail。
最後は諦め。

感想

zakuroさんがN+1問題を解消する速度が早すぎる。
僕はなんかNginxとMysqlの設定を適当に弄ったりプロファイラ動かしてボトルネックになってそうな部分を探すだけをやっていた。
Pythonで非同期なんか直感的にかけない.....(慣れてないだけかも)
最後のベンチマークが詰まってるの、APIが返せてないんじゃないかって思うけど違うのかなぁ.....
というか、分散させる話は....? (ちゃんと時計を見て計画的にやりましょう)