詩と創作・思索のひろば

ドキドキギュンギュンダイアリーです!!!

Fork me on GitHub

ISUCON5 本選に参加して7位に終わりました #isucon

表題のとおり、ハロウィンの夜ゾンビ化した渋谷の街でヒカリエに取り残された俺たちは、ISUCON5本戦に参加してきました。

予選はこちらをご覧ください:

motemen.hatenablog.com

チームは id:wtatsuru (たつる先生)と id:ichirin2501 (いちりんちゃん)とで組んだ「2nd Party Cookies」。

結果は上記のように7位。8万点台に乗らなければ勝負に絡んだと言えず、一時は7万台まで伸ばしていただけに悔しい結果となりました。以下、当日やったことをふり返ります。

初動

開始時刻になってサーバにアクセスできるようになると、wtatsuru が諸々のセットアップをしているあいだにアプリケーションの挙動をチェック。マイクロサービスを使ったウェブサービスで、ユーザの登録情報から複数の HTTP API を叩いて画面に表示する、というものでした。

データベースが Postgres だったのには戸惑いましたが、Perl 実装に切り換えて各エンドポイントごとの処理時間を見ると直列に外部リクエストを発行している GET /data が支配的だったのでまずはこちらをやるのが先決だろう、という結論に達しました。

最初の1時間が経ったところで作戦会議と決めていて、この時点でまだ時間があったので /data の処理をクライアント(ベンチマーカー)に分散してみたらどうだろう、というアイデアを検証するため JavaScript を書き換えたところ、fail。あくまでサーバサイドのアプリケーションをチューニングせよという問題だと分かりました。

まずはキャッシュ

外部 API の性質を把握するのが第一だろう、ということでエンドポイント定義を見るとすべて GET だったので、これはキャッシュしてよかろうと memcached に無期限キャッシュするように。するとスコアが10倍くらいに跳ね上がりました。fail がなかったので方針は間違ってないのだろうと思ってしまいましたが、後にキャッシュが古すぎるという理由の fail が頻発し、苦しむことになります……。

ken および ken2 API は見るからに郵便番号から住所を返すものだったので、どこかに元データがあるのだろうと思って探したところ、日本郵便の提供する CSV ……を加工した CSV が 郵便番号データのダウンロード - zipcloud で提供されているのを知り、Postgres に COPY 文でインポート、住所を非 HTTP API 化したところ、またスコアアップ。その後3台構成にすると3万点台に乗って暫定1位となりました。

ダメゾーン

ここでひと息ついて、リクエストの並列化やアプリの CPU 率の低減が考えられる次の課題だろうという話をし、motemen ichirin2501 それぞれが自分のブランチで作業することにしました。検証にはどれか1台にブランチをデプロイしてベンチを回し、スコアが上がればマージする、ということをすでに行っていて、そのフローを踏襲したのですが、3台構成にしたままこれを行ってしまったのがよくなかった。他にも混入していた不具合等があり、この辺りから fail が連発して、有用な変更を何一つ入れられませんでした。

持ち直し

みんなが同時に喋りだしたところで wtatsuru 先生が落ち着いて、まずは master 通る状態に戻しましょう、と言ってくれたので、元に戻して通ることを確認。このひと言には助かった。これで一同、気を取り直せました。

motemen は AnyEvent による並列化を断念。初期化処理をミスっていて郵便番号データがベンチのたびに増大し、メモリを圧迫していたことが分かったので修正する(これは initialize が30秒を越えたのを調査していて気づけた)、静的ファイルの配信をnginx 化したつもりができていなかったので修正する、など、凡ミスを修正して7万点台に。暫定3位。

またキャッシュ

……と喜んでいたら、アクセス数が増えた結果か、また fail するようになってしまいました。レスポンスの内容が古い、というメッセージ。これは memcached の初期化を忘れたときに一度見たものだったので、キャッシュを適切に破棄すればよかろう、と、キャッシュ秒数を調整することに。ここでようやく外部 API のレスポンスを curl で直接覗いたのだけど、この時点で残り2時間、遅かった。If-Modified-Since ヘッダも付与してみたがレスポンスに変化がなかったので、使えないと判断してしまいました(終了後じつは対応していたと明かされたので、リクエストの組み立てがおかしかった模様)。

tenki API が3秒ごとにレスポンス内容を変化させることを観察し、キャッシュ時間を3秒、1秒と変化させてみましたが fail。ここは実装をミスっていたのだとしか思えない。そうする間にデッドラインが近づいてきたので、成功していた頃の5万点台に戻すため、静的ファイル配信の最適化をやめるという苦渋の決断をしました。これで提出、あとは前出の通りの結果となりました。

感想

本戦には最近の2回を参加していて、その時と較べると確実に進歩しているけれど、まだまだ。今回はけっこう準備していったつもりだったし、方針も間違ってはいなかったはず。ただ、チームワークとか冷静さの部分で他のチームに遅れを取ってしまったように思えて、短い時間で結果を出すには、各自のレベルや経験はもちろん、やはり司令塔が必要かなと感じました。あと /data を Go で並列化する、とかは思いついていたかった……。

さて ISUCON 勝利への近道は出題者サイドに立つこと……だというもっぱらの噂ですので、まずは社内 ISUCON でも開いてみたいな、と思うところです。と少し考えてみるだけで、問題を作るのもベンチマーカーを準備するのも大変そう。今回は予選本選ともベンチマーカーが最高に快適で、問題も楽しかったです。主催者側のみなさん、お疲れさまでした&ありがとうございました!

はてなで一緒に働きませんか?