水深1024m

技術的なメモとか日記的なもの

ISUCON5 本選でトップスコア fail した

ISUCON5 に .dat として @y_matsuwitter@TakatoshiMaeda で参加してきました。本選6位だった昨年に引き続き、今年で2年目です。 幸運にも予選を(2日目)1位で通過することができてたのですが、主にネットワークやミドルウェア周りを担当していた自分としては結構なニート状態だったので、本選ではもうちっとは貢献したいなーという気持ちがありました。

Go - ISUCON5予選でスコア34000を出す方法 - Qiita

で、本選ですが、アプリケーションレイヤでやったことは @y_matsuwitter の記事にほぼ全て書いてあります。 ISUCON5本選にてスコアトップの18万点でfailしました - Qiita

サーバ構成に関することも書いてあるので僕が記事書く必要もなさそうですが、せっかくなのでやったことをちょこまかと書きます。

基本的なセットアップ

@TakatoshiMaeda が完璧に仕上げたセットアップスクリプトで一撃でした。Ubuntu 15.04 + systemd だった予選と違い Ubuntu 14.04 + upstart + supervisord だったわけですが、そのへんの差異も特に気にせずドーンという感じです。 @TakatoshiMaeda++

開幕 tcpdump

改善に限られる時間が限られており、特に今回の問題では外部 API という要素が入ったこともあって、可能な限り早い段階でそれらを含めた全体像を把握する必要がありました。 アプリケーションレイヤの改善を僕以外の二人に任せていたので、アプリケーションの変更をせずある程度の分析を行っておきたいと思い、ベンチマークのパケットダンプを取っていました。 把握できたのは大体以下のようなことです。

  • ベンチマーカが送ってくるヘッダ、リクエストパターン
    • Accept-Encoding: gzip とか (最終的には忘れてたけど。。。)
  • 外部 API が返してくるヘッダ
    • リクエスト/レスポンスの仕様
    • tenki API が Last-Modified を返していたのはこの時に分かってた
  • 外部 API に接続するときに DNS リクエストをしていない
    • /etc/hosts に書いてあった
    • ハードコードしても問題ない

まあ、初手の分析としては十分なのかなーと思いました。 で、API の中にわざわざ HTTPS のエンドポイントが含まれてるのを見かけたので、おもむろに nghttp2 とリンクした curl をビルドして接続したところ HTTP/2 接続に成功しました。ベンチマーカーや外部 API に仕込まれていた要素については開始45分くらいで大体把握できていたと思います。

js の改変

一通りのチェックが終わり、大体の方針を決めて @y_matsuwitter が作業に入り、僕と @TakatoshiMaeda は airisu.js から行う XHR 先を分散できないかという検証をやっていました。結果としてそもそも js の改変そのものがどのようなレベルでも許されていなさそうなことが分かったのですが、CORS 周りの設定にハマり少し時間を無駄にしてしまったのが後悔でした。そもそも静的ファイルの変更がどのくらい許されるか自体はもっと小さな変更で確認できたはずで、検証すべきことを切り分けず最小限のことだけをやらなかったのは大きなミスでした。

ミドルウェア類の設定

正直ここについては、ざっと絵を描いた段階でチーム3人とも意見が一致していたこともあり、"あとは書くだけ"状態だったので特に考えることもハマることもなかったです。nginx, Redis, kernel 周りの設定など必要のあることをやっただけ。 @y_matsuwitter の Redis 実装をマージして1台で実行して13万点を超えたので、そこから複数台構成になるように修正。 先頭に置いた nginx (静的ファイル配信 + リバースプロキシ) で CPU affinity を固定してあげたりするとこのマシンは CPU を使い切れる状態に達しました。

終了まで

ちょうどこのタイミングで行われたベンチマーカーの修正により "ちゃんと fail するようになった" バグが最後まで取りきれずに敗北することになります。 正直この修正が発表された時はあまり真剣に考えてなかったのが痛かったです。会場内で2つだけ用意された会議室 (先着順で使える) を扉を閉めて使っていたこともあったのかもしれないけれど、アナウンスはちゃんと聞いて自分たちへの影響を確かめようというのは反省でした…

ミドルウェア側での大きな構成変更は3台構成にしてからはほぼなく、先述のバグの他にも fail がいくつかあったため他の2人にその修正をひとまず任せ、再起動耐性のチェックを行いました。バグが最後まで取りきれなかったため、再起動テストをそもそも行うことができなかったのですが、結果として再起動後もきちんと動いていたようなのでまあここはよかったのかな。。。 その後はバグ取りのサポートなどをしていましたが、結局取りきれず提出。

他にやりたかったこと

大体のことは @y_matsuwitter の記事に書いてあるのでそちらを。 他には ken API のデータを見ていて、ああこれはみんな大好きKEN_ALL.csvじゃないか、ということでこれを作りなおしてそもそも API リクエストをやめる、という案はありましたが、それ以前の問題が多すぎたので却下。

感想

Cache-Control に泣いた去年と比べ、初手でそういった目に見えないポイントを洗い出すことができていたのは進歩だったかなーと思います。スコアがどうだろうと fail というのは変わらず、”僕と @TakatoshiMaeda がこまい改善を積み上げておいて @y_matsuwitter がかめはめ波を撃つ” というのが毎回のスタイルではあるのですが、もっとやれることはあったなーと思うし実力不足を痛感しました。 あと1つのfailがなければスコア的には優勝だった、というのは事実そうなのですが、このfailを落ち着いて潰せるかどうかというところに大きな差があったわけで、そういう意味でも「次やったらきっと勝てる」というレベルの話でもないよなーという実感があります。悔しい。

とはいえチームとしての動き方も毎回良くなっていることは確かなので、来年は足回りの力をがつっと上げて優勝しに行きたいと思っています。

今回は、予選本選通して特にベンチマークがとても快適だったのが印象的でした。 本選の Microservices 問題も、自分としてはリアリティのある問題だったこともあり楽しかったです。 予選、本選、懇親会 (ハロウィンで渋谷の治安が崩壊してましたが) どれをとっても最高でした。関係者のみなさまありがとうございました!来年もぜひよろしくおねがいします。