Unyablog.

のにれんのブログ

ISUCON9 予選に参加した(failed)

最近は O-Ku-Ri-Mo-No Sunday! にはまっている。めっちゃ良くない?

ということで先日 ISUCON9 に参加した。

isucon.net

チームは :innocent: で id:wass80, id:utgwkk と参加した。

全体的な話は utgwkk の記事を参照。

utgwkk.hateblo.jp

自分のやったことは大体以下の issue に書いてある。レポジトリも以下参照 *1

github.com

トラブル集

今回もいろんなことが起きたので列挙してみる。

サーバー構成を1台と勘違いする

全員が [重要] と書いてある場所を読み飛ばしてスコアの計算方法ばっかり気にしていた結果、複数台構成ができないと思い込んでいた!

コンテスト中は「これ複数台勝手に立てたらどうなるかな〜」とか言ってました。1台だったのでインフラ担当の自分は途中暇だった。

たとえ構成は1台限定だったとしても、3台立ててそれぞれ作業用にしたら良かったなあ、という反省も。

VSCode Remote をやめることで得点が10倍になる

なんか 410 点ぐらいしか出なくておかしいな〜とか言いながら htop を見ていたら VSCode Remote がめちゃくちゃ CPU 食ってた。やめると 4100 点ぐらいになって最大のブレイクスルーだった。

Gunicorn のオプションを間違えてプロセスが大量発生する

Gunicorn の --worker-connections を 10000 にしようとしたときに、間違えて -w 10000 として ワーカー数が 10000 になった。当然プロセスが大量に生まれるので、アクセスするとめちゃくちゃ重くて Load average が 170 になった。

sudow すらも謎のエラーで使えなくなったので、 root で入って systemctl kill した。 systemctl は kill できるので最高!*2

uWSGI の restart が効かないので reboot を繰り返す

いろいろあって Gunicorn を uWSGI に載せ換えたのだけど、なぜか restart がハングするようになってしまった。面倒なのでサーバーごと reboot することで restart の代わりにしていた。後述の Redis と同じ理由かも?

途中から systemctl kill --signal=9 すると restart=true で立ち上がることに気付いたのでそれを使うようにした。 systemctl は kill できるので最高!*3

Redis が立ち上がらないので memcached にする

Redis を apt で素朴に入れたけど apt installsystemctl restart がハングしたので諦めて memcached 入れた。おそらく↓の話っぽい。

Redis は kill して purge した。 systemctl は kill できるので最高!*4

並列 http アクセスライブラリを入れようとして未実装であることに気づく

transactions で外部 API を呼んでいるところが直列で遅かったので、並列にしよう!ということで検索して出てきた httpx というライブラリを使うことにした。

github.com

www.encode.io

このドキュメントに即して実装を始めたのだけど、20分程度して実装が終わりつつあったときにドキュメントにある警告文の存在に気付いた。

Warning

This page documents some proposed functionality that is not yet released. See pull request #52 for the first-pass of an implementation.

https://www.encode.io/httpx/parallel/

悲しいね〜。文章読めるようになる必要がある。

Gunicorn や uWSGI を使うと点数が伸びなくなる

途中、デバッグのために Gunicorn じゃなくて Flask の app.run() を直接使っていた。それでうまく伸びていたのだけど、Gunicorn にした瞬間に点数が1/10になった。uWSGI でも同様で、これについては今も謎。コンテスト中盤からずっとネックになっていて、終盤ドタバタした遠因になったと思う。

今見たら app.run() の方は threaded=True になってるので、10 workers の Gunicorn とはいろいろ違ったんだろうか。でも初めは上手くいってたので謎。

並列処理たちとのたたかい

gthread

Gunicorn は gthread を使うことができるのでなんとなく設定して使ったら動いているように見えた。ただ、大量に受け取りすぎて 499 ばかり返すようになってしまったので、もう少しチューニングが必要そうな雰囲気だった。

nodejs でも同じような悩みがあるのだろうか。それとも真にイベントループな言語は関係ないのだろうか...。

transaction

今回は transaction での外部 API が直列でめちゃくちゃ遅いのが課題になっていた。Python の並列処理にいい思い出が無いので、そこだけ nodejs に流すことも考えたものの、cookie やらを考えて結局 Python で行うことにした。

ただ Python の async await ほとんど分からないので難航。出たの最近だし機能もどんどん増えてるので、ぱっと調べるには向いていなかった *5

結局最後の最後*6には aiohttp 使って勘でなんとかなった気もするけど、他のエラーでてたので分からなかった。

次回は go か node でやってもいいなあ、でも今回で async への理解深まったので Python で使える気もする。自分が一番好きで詳しい言語である Python によく分からないメジャー機能があるのがとても悔しい…。

良かった点

反省点ばっかりなのもアレなので良かった点も。

  • 遠隔で行ったが、専用ディスプレイにずっと遠隔者のディスプレイを写していた
    • スムーズな情報共有ができたと思う。全員同じ場所にいても有効だと思った。
    • 次は VSCode Liveshare とか使ってみたいな。
  • バグったときのために、オリジナル版を別ポートで動かしていた
    • バグったときにレスポンスをオリジナル版からも取得して diff する、といった活動を行っていて低コストながら高速にバグを発見できた
  • 計測やログイン環境のセットアップは順調にできた
  • pt-query-digest や kataribe などでボトルネックの計算をちゃんと行っていた
  • 定期的に git commit していたので容易に rollback できた
  • スコア計算方法の部分はちゃんと読み込んでいた
  • 手が空いたときに弁当を買いに行くという判断をした
  • 昼飯をちゃんと食べた
  • 楽しかった

その他

@チーム

今年もありがとうございました。 wass の迅速な方針決めや実装は頼りになったし、utgw が N+1 や index をバシバシ解決していく姿は最高だった。来年も頑張りたい!!

@運営

今回も楽しかったです!

バランスの良い問題になってて良かったです。isucari や還元キャンペーンなど、いかにもメルカリっぽい話題でニヤッとしました。あと得点がレスポンス数ではなく取引価格の合計なのも、実際のサービス目標感があって良かったです。

運営・インフラ提供・問題作成者の皆さん、ありがとうございました!!

感想

今年はあんまりやる気なくて練習もせず適当に始めたのだけど、実際やったらめっちゃ楽しいし、負けたらめっちゃ悔しい。 ISUCON4 からずっと参加しているけど、最高のコンテストだと思う。

次回もあれば絶対に参加したい!!!!!本戦行くぞ!!!

*1:async wait 実装は入っていない

*2:そういう話ではない

*3:そういう話ではない

*4:そういう話ではない

*5:asyncio.sleep() じゃなくて sleep() つかって上手く行かないじゃん!とか言ってた

*6:17:59 ぐらい