ISUCON9に出場してきた。そして敗北してきた。
fujiwara, tagomoris, 自分という大人気ない面子で出場して負けてしまったので、非常に悔しい。 大した活躍が出来なくて申し訳なさで一杯である。 最終スコアは5000ちょいぐらいでしたが、3台分のリソースを全然回せなかったので、アプリサーバのCPUまでネックを移せれば予選突破レベルだったかなあ……。
分かっていた明らかな問題点
- DB負荷が高い
- DBのロックが長い
- APIのシーケンシャル呼び出しにより待ち時間
- loginの負荷
- 静的ファイルの配信
やれたこと
- N+1自体の解消
- マルチスレッド化してAPI呼び出しの待ち時間を最小化
- 静的ファイルをnginxで配信
- categoryをオンメモリに乗せる
- 複数台構成化
失敗
N+1解消手法の選択ミス
N+1を解消するのにJOINを使ってしまったことが一番問題だった。
フロントからのリクエストを変えられないので、ページネーションをするためにcreated_atのorder byの範囲を絞らないと何をやってもDBネックが消えなかった。
JOINのパターンが複数パターンあったので、ORDER BY狙いのindexが全然効かせられなくて、時間使い切ってしまった。
もう少し早めに方針転換してクエリをバラす方向に触れれば良かったかもしれない。
単純にitemsだけORDER BYが効く様にした上で、IN句を使って他のエンティティを取得しアプリ側で結合するのが妥当だったと今なら思う。
ソースコード確認するまでの時間
最初にAlibaba Cloudのインスタンス起動に失敗し起動がロックされてしまった。
結果、インスタンスを起動してソースコードを得るまでに1時間ぐらい時間がかかってしまった。 また、ソースコードの分量が多くて読んで状況を把握し、実際に作業に入った時点で昼前ぐらいだったと思う。
完全な負け惜しみだが、そこで無駄にした時間が無ければもう1手打てたかもしれない……。
エラーハンドリングの適正化
エラーハンドリングがかなり厳しいコードで、地道にコード直してAPI呼び出しやスタックトレースがまともにロギング出来る様に最初に改修しておくべきだった。
エラー発生時の情報取得が上手くできてなくて、かなりの時間を無駄にした。 結果、出来ることがかなり減ってしまった。
上手くいったこと
モリスさんがマルチスレッド化をサクっと実装してくれたため、そこで最低限のスコア上昇は得られた。 そこはやれば上がるのは分かり易かったし、我々はこういうコードを書くのは最近得意であるw
というわけで、ここは数少ない上手くいった箇所だったと思う。
反省と負け推しみ
ある程度やる事自体は見えていたのだが、完全に手数が足りなかったり、DBネックを潰し切れなかったのが致命傷になってしまった。 bcryptを別アルゴリズムにしていいというのは完全に思い付いていなかった。そこに負荷がかかっているのは分かっていたが、ルールに対する思考の柔軟性が無かった。
総合的に柔軟性を失っているなあということを感じた。後、面倒臭いことに我武者羅に突っ込むのを躊躇してしまったかもしれない……。 おっさんになるとはこういうことなのかと思った次第である。
そして、言い訳と負け惜しみを書いておくと、私自身クライアントから直接アクセスが来る様なWebアプリケーションを最近全く書いてないので、完全に勘とか手の早さを失っていると思った。
インデックスという概念が無い全スキャン前提のDWHとかパーティションキーでデータを取得するCassandraとかに対して1000万件オーダーでデータを取得する様なクエリばっかり書いてるし、データパイプラインのスケーラビリティとかストリーム処理に関するコードばかり考えていて、Webのページネーションとかをちゃんと実装する、みたいなことから遠ざかって久しい。
昔取った杵柄みたいなものでいつまでも戦える程簡単なものではない様だ。
これはISUCONという大会が良く出来ているという話でもあるので、悪いことではないだろう。 しかし、やはり負けるのは辛い。特にチームメンバーが強力だっただけに辛さが3倍である。
次回はどうだろうなあ。仕事がまたコンシューマアクセスが来るWeb領域に戻るまでは諦めるかもしれないw