wtatsuruの技術方面のブログ

はてなスタッフ id:wtatsuru です。日常ブログはこちら https://tatsuru.hatenablog.com/

ISUCON5 本戦出場してきました

ISUCON5 本戦に、同僚の id:motemen id:ichirin2501 と一緒に 2nd Party Cookies として出場してきました。
結果は7位に終わり、トップの fujiwara 組に3倍近い差をつけられてしまう結果となってしまいました。

まず全体

今回の題材は、社長が作ったマイクロサービスアプリの改善。予選の凝ったDB設計とアプリからはがらっと変わって、DBは PostgreSQL に変わったもののそこは焦点からは外れ、外部APIコールの最適化がメインのテーマとなりました。
予選に続いてとてもいい問題で、ベンチマークもスムーズで非常に楽しめました。運営の皆様は大変だったと思いますが、ありがとうございました。
個人的には、初動や全体の方針はそこまで悪くなかったものの、インフラ担当としての開発支援や視野の広さ、実現に持っていく力という部分での差の大きさを痛感しました。

当日の動き

Slack ログを見ながら、自分の動きを中心に振り返ってみます。自分以外のやつはちょっと間違いあるかもしれません。

開始から初動
  • 11:00 開始
  • 全員のログイン設定、デプロイまわりを整える
  • 計測系のパッケージ入れたり最低限のセットアップ
  • nginx のログ調整で alp でのアクセスログ解析準備
  • Perl 実装への切り替え、一発目のベンチマーク。1102
  • 11:30 くらいから最初のログを見つつ、DBの様子・サーバの環境を観察したりして作戦を考える
最初の作戦会議

1時間くらい観察したところで作戦会議。

  • `/data` で外部APIを叩きに行くところが支配的。リソースぜんぜん使い切れてない。ここをキャッシュするとよさそう
  • DB が PostgreSQL で驚いたが、データ量も小さく触らなくてもよさそう。 endpoints テーブルをハードコードする以上のことはあまり必要なさそう?
  • APIも手元から叩けないし PostgreSQL そのままだと通らない(結局プラグインが必要とのことでした)で、手元環境作るのけっこうしんどいと判断。3台あるので実験用には別のものを使う
まずはやれるところを

やり残したこと、まずやるとよさそうなことの準備を進める。

  • 外部APIの接続先とリクエスト時間をログに残して観察。キャッシュで50倍くらいまではいけそう、などと検討
  • nginx で keepalive, static file 配信(実はミスってた)
  • 1台なのでまずは Gazelle + Unix domain socket 化
  • memcached を1台用意してキャッシュする
  • zipcode も郵便番号と住所なんだしAPI叩かなくていい?じゃあDBに入れるか、という大きめの改善を by id:motemen さんがサッと入れてくれた。かっこいい
  • そろそろCPUを使い切ってるので、3台使ってみる。PostgreSQL 外部から接続でちょっと手間取ったが、これ以降は PostgreSQL 全く触っていない。

キャッシュを入れた時点で14519で暫定1位、zipcode で18768、全台使って 33774。このへんで14時過ぎ、勢いづいてくる。
いったん作戦会議を挟む。

ゆきづまり

特別賞が10万点ってことは、そのへんまではいけるはず、もっと飛躍が必要ということでいろいろ考える。

  • static file のアクセスが目立つので gzip 入れて etag / expires などで改善という話を id:ichirin2501 とする。そして効かなかったので戻す。config のちょっとしたミスで効いてなかったことがあとで判明。。
  • JSON parser 負荷高い、という仮説のもと id:ichirin2501 が改善を始める
  • nginx のCPU使用率が目立つ。クライアントの keep-alive はわりときいてる。worker 2, Starlet にして proxy-app 間を keep-alive をきかせてみる。
  • API リクエストの並列化は優先度高いのでは、という相談をしてそちらは id:motemen さんに依頼。
  • サーバ構成で DB と nginx は分けてみた

何だかスコアが伸びないし fail しまくる、nginx 499 出まくっている、という現象に悩まされる。並列リクエストの方は、再現性の微妙なエラーで行き詰まる (endpoints の1つが1コネクションしか受け付けない、ということだったのでそれもあったかもしれない)。さらに zipcode のデータを全部メモリに読み込んでいた結果、swap 発生で全台死にかける、など散々な状況。デバッグしにくいものを実機上でデバッグしていたりして、互いにロックしてしまったのがもったいなかった。

復活

いったん元に戻し、あらためて一つ一つ見ていく。

  • static file の配信まわりでミスっていたのを id:ichirin2501 の指摘により修正。マジ感謝
  • proxy-app 間の keepalive をやめることで 499 大幅減少。間のいろいろな改善が効いて 52097。3位くらいだったと思う
  • nginx ミスがわかったので再びクライアント最適化系を入れる。sys 減らそうとネットワーク系も少しいじる。

記録残すの忘れてるが、16:30過ぎくらいに 76000 くらいまでいってた気がする。トップまであと5万よっしゃいくぞ、と盛り上がった。この時点でもまだサーバリソースは使い切れていなかった。

失速、敗北
  • 70000こえたあたりで、fail が目立ち始めた。API の内容をキャッシュしすぎている、というようなエラー。
  • よく出る Tenki API のキャッシュを切ってみるものの、スコアが1桁落ちる。
  • 一度再起動試験を入れて無事に成功。しかしスコアは全く伸びず。。
  • id:motemen id:ichirin2501 2人がかりのキャッシュ対策を見守りながら、最後の1時間でマージするちょっとした改善の準備をさっと行う
  • API の傾向とレスポンスを観察。tenki の Last-Modified が3秒おきなのを把握。If-Modified-Since つけてもダメ、と思ってしまったが、何かミスがあったような気がしてならない。。
  • 特定のAPIのみのキャッシュ期間の調整がうまくいかない。バグがあったのかもしれない
  • しょうがないので static file 関連の最適化を外し、わざと遅くすることで fail を防ぐ。5-6万あたりで安定して通るようになった

最終スコアは 57,492。fail してもおかしくない状態だったし、悔いの残るスコアになってしまった。

反省点

具体的な反省点。

  • 外部APIの特性をギリギリまで見ていなかった。そこが焦点になった時点でAPIの特性を観察しておくべきだった。
  • 開発効率へもう少し気を配りたかった。開発環境がない、デプロイが微妙に遅いなどの点。トップの fujiwara 組は、サーバ上に Squid を立てるなどして手元で開発できるようにした、とのこと。そのあたりにコストをかけておきたかった。
  • もう少し全体を見て、方針のリードをしたかった。とくに本戦では配置と最適化のポイントの絞りこみが重要なことはわかっていたので、引いた目線へのリソース配分はすべきだった。

これから

2年前のISUCON3 よりは手ごたえがありましたが、もうひと伸びの必要性を感じました。上位は全て出題経験者だったし、ひとまず社内ISUCONなんかで出題経験を積みたいなーとなんとなく思っています。
あとは普段の仕事を真面目にがんばるだけですね。。要素技術についてはそんなに負けてないと思うので、幅を広げる・考察を深めるというあたりに注意してがんばっていきたいと思います。

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