ISUCON に今年も出場して、めでたく予選突破できた。チーム名は 😇😇😇 で、チームメイトはいつもと同様 utgwkk と wass80。
チームメイトのエントリは以下。
レポジトリは以下。
やったこと
いつも通り自分は Schema とかアプリケーションはあまり見ずにインフラに徹していた。New Relic も全然見てない。
- ssh config 書く
- ユーザー作る
- pt-query-digest や netdata 入れる
- レポジトリ整備(スクリプトや symlink)
- 余計なプロセス消す
- Nginx で Bot の ban やったり proxy_cache やったり
- sysctl などのチューニング
- MySQL のチューニング
- クエリキャッシュとかスロークエリ出すとか
- MySQL の複数台分散
いろいろ
Nginx
proxy_cache_valid
を設定しないとキャッシュが効かなかったけど本当かな?
MySQL
今回も色々悩まされた。 symlink でやったら何故か上手く行かなくなったり、GRANT で手間取ったり。
一番時間を食われたのはインスタンスをまたいだ接続ができなかったことで、ポートも開いてるし許可もしてるのにサーバー側に Bad handshake
エラーが出て全く接続できなかった。
色々見た結果、 最初に MTU を雑に 9000 に設定していたのが原因で、 1500 に戻したら直った。 PMTUD やら TCP MSS やらが動かなかったんかな~。
クエリキャッシュ
今回は Write が少ないためクエリキャッシュがとてもよく効いてくれた。 600点が1500点ぐらいになって一時は2位になってたはず。
query_cache_size
だけではダメで、 query_cache_type = ON
にしないと動かないことに初めて気づいたのだけど、今までずっとミスし続けていた…。 MySQL 8 にはクエリキャッシュ無いのでこれからはあまり使うこともなさそうな新知見。
複数台分散
今回は MySQL がボトルネックだったので複数台分散をどうするか考えていた。結局 *sqlx.DB
を複数持って、書込側はレプリケーションせずに両方に並列に書き込む形に、取得側は2台からランダムに取ってくるようにした。
準同期レプリケーションや、nginx の proxy とか LVS を使っても良かったのだけど、アプリケーションがそこまで大変ではなかったのでそちらの変更で済ますことにした。
一見ヤバそうな方針だけど結果的にはちゃんと動いてくれて、スコアを伸ばすことができた。goroutine 最高*1。
とはいえ、垂直分割が一番賢いよなぁ。コンテスト中は全く思いつかなかった。
その他
Go を使った
今までずっと Ruby か Python でやってきたけどバグったときの修正が大変だった。Go は早いし、コンパイル時に型チェックもしてくれるし、IDE は整っているし最高だった。過去の回でよく悩まされてきた謎のエラーもほとんど起きずに、スムーズにスコアを伸ばすことができた。これからも ISUCON では Go を使うと思う。
終盤の Fail
終盤に複数台分散を入れたら時々落ちることがあったけど、最終的には安定して通るようになって良かった。とっさの reboot が効いたのか、 sysctl を全部戻したのが効いたのか、MySQL の innodb_doublewrite あたりを全部デフォルトに戻したのが効いたのか。
Mitigations の無効化
Mitigations を無効にするカーネルパラメータを入れると早くなるという話題があって、やることも考えていたのだけど、
grub-install
が必要で流石に怖くてやめた。全然点数出なかったら最後に試してたかも。
今回も予選にも関わらず複数台構成ということで、インフラ担当の自分としてもやりがいのある問題でした。運営のみなさんありがとうございました!本戦もよろしくお願いします!!
2年ぶり3回目の本戦出場でとても嬉しいし、本戦もこの調子でやっていきたい!
*1:ミスって wass に直してもらったけど😇