ISUCON8 予選に参加した

ISUCON8 の予選に去年と同じメンバーの @chigichan24, @euglena1215 と,チーム 牛久大仏「う~ん顔採用w!」 で参加してきました.

最終スコアは 4000 点くらいで,予選敗退です.スコアも跳ねなかった.様々なボトルネックが把握できたし様々な手法も試したがそれらは効果的な解ではなかった.悔しいですが忘れないうちに書きます.策は打ったが結果にコミットできなかった記事です.答え合わせをしたい人は回れ右.

※ ISUCON とは,Iikanjini Speed Up CONtest の略で,制限時間 7 時間で互換性を保ったまま (つまり,同じ入出力ができる状態で) 与えられたアプリケーションを高速化するコンテストです.

チームメイトの記事は以下です. @chigichan24 の記事では Nginx や MariaDB などのミドルウェア改善の視点から全体を振り返った記事が書かれています. chigichan24.hatenablog.com

@euglena1215 の記事ではアプリケーションコード改善の視点から記事が書かれています. euglena1215.hatenablog.jp

プロローグ

前回は予選突破できたものの課題は山積していた.予選は頑なにサーバと向き合い続けたらなんとか突破できた.が,本戦ではアプリケーションをゴリゴリ修正する必要があったので,歯がたたなかった.反省点は概ね以下の通り.

  • アプリケーションコード修正の優先順位が低かった
  • レギュレーションの見落としが多かった (特に予選の帯域制限や /fetch の扱い)
  • N+1 解決の優先順位が低かった
  • 初期の準備に時間がかかりすぎた
    • git ready にするまで時間かかったりパスワードミスって fail2ban に BAN されたりした

すげー悔しかったので今年の ISUCON は 6 月くらいから始まっていました. esa を使って情報共有もした.esa 便利ですよ.基本的に社会人とは経験の差がすごいので,とりあえず真似できるようになろうと強豪チームの実装ステップを追って共有した. f:id:k5342:20180917112842p:plain

戦略

今年はアプリケーションを治そう,他のつよいチームと比較してもアプリケーションの修正が少なかったのは分かっていたし,とりあえず Nginx と向き合い続けるのは危険じゃないか,という考えから以下のような方針でいった.

  • レギュレーションをしっかり読む
  • Nginx はお気持ち程度にする
  • N+1 は確実に潰す
    • というか,アルゴリズムレベルの改善が一番効くことが多いのでしっかりやる
    • 一人で無理そうならペアプロを導入してみる
  • 計測を確実にする

計測は前回は完全に雰囲気でやっていたので,ちゃんと事前練習した.ツールも覚えた. あと僕は基本的に怠惰な人間性の持ち主なので,去年の fujiwara 組のように Docker Compose を用意するわけでもなく全部サーバサイドで修正したがる.前回はサーバサイドで全員が同じユーザで開発したので history 汚染や意図しない git checkout がやばかった,ので,開始直後に全員分の公開鍵や dotfiles を突っ込むのと個別のユーザを作る Ansible Playbook を書いて実戦投入した1.この作戦は前半の焦りを緩和するのに大いに役立ったと思う.チームメイトには Vim 使用を強制した.Vim 利用者増加にも貢献できたと思う.

当日

予選はそういうつよい気持ちで参加した.今回は torb という映画館のチケット取得用 Web アプリで,一般ユーザが使うインタフェースと管理画面が付いた実装です.平成狸合戦バブル経済.アプリは ConoHa のサーバ上に乗っていて 1GB RAM で CPU は 1 コアのサーバが各チームに 3 台与えられました.パブリックな方向には 50Mbps とキツめの帯域制限があります.

僕のチームは Ruby 実装を使っていて最終的な構成は以下のような感じです.

  • isu1: DB (MariaDB)
  • isu2: App (Nginx as Load balancer + torb.ruby)
  • isu3: App (Nginx + torb.ruby)

今年はアプリケーション修正に重きを置く作戦で,具体的な担当を決めていませんでしたが,最も作業量が多かったものを上げるなら k5342 → 計測,chigichan24 → サーバ設定最適化,euglena1215 → アプリケーション修正 といった感じでした.チームでやったことは以下のとおり.

# k5342 chigichan24 euglena1215
10:00 Ansible を走らせる サーバを眺める レギュレーションを読む
10:15 yum install nginx
10:40 複数台の .conf と App を Git 管理下にする アプリケーション修正準備
10:45 DB にインデックスを貼る
11:00 複数台で git push できるようにする Nginx 化
11:15 80 と 22 ポート以外が開かない原因調査 Nginx の max_connections 増やす kataribe でプロファイルをとる
12:10 get_events の N+1 を考える 静的ファイルに Cache-Control 設定 get_events の N+1 を考える
12:30 euglena1215 手伝う euglena1215 手伝う ペアプロで get_events の N+1 を治す
14:41 MariaDB の max_connection 増やす get_events の N+1 を消す
get_event の details 無し版をつくる
14:53 DB: isu1, App: isu2 に構成変更するも fail get_event の N+1 を消す作業
15:00 isu2 の GET /initialize がやたら速いことに気づく
15:00 GET /initialize がサイレントにコケる原因調査
15:10 DB: isu1, App: isu2 完成
15:19 SELECT のトランザクションを消してみる
15:20 App でやたらスワップしてることに気づく
15:25 App を修正して csv のメモリ使用量削減に挑戦
16:00 やっぱ get_event 完全に直さないとキツい? メモリ足りひんから MariaDB も控えめにチューニングする Puma のワーカ設定変更芸人
17:00 とりあえず三台使い切ろう
17:07 DB: isu1, App: isu2, isu3 完成
17:20 再起動チェック
17:45 祈りを捧げる ベンチガチャ ベンチガチャ
18:00 終了 終了 終了

去年と違って複数台構成がシュッとできたところはすごくよかったと思うし,インデックスや静的ファイル配信みたいな基礎的な部分も序盤でできていた点は成長だと思う. 一方で時系列に治してみてみると僕があまりアプリケーションコード修正に参加できておらず,反省点が活かしきれなかった.

フィーリングに頼らず計測をうまいこと活用できたと思っていて,ボトルネック把握に特に役立てられたと思っています.例えばベンチマーク中にページアウトがアホほど起こっていてこのせいでアプリが律速していたことに去年の自分は気づけなかったと思う.

f:id:k5342:20180917141608p:plain

しかし,計測がうまくいったとしても,それをどう解決すれば効果的かというフェーズではまだまだ取りうる選択肢が少ないかなというのと,それを短時間で実現できるかというのはまた別の話ですね,これらは今年痛感した課題.

あと get_events 修正用の SQL クエリをシュッと書いた (間違ってないクエリだった) んだけど,デバッグするときに参考実装で表示されているイベントと違う event_id でデバッグしていて 結果が違う!w とか騒いでいて (当たり前),有りもしないバグを探し続けた結果 1 時間くらい溶かしたのですげえ悔しい.そこはペアプロしてたのに最初気づけなくて,3 人のリソースが空振りした...ように思えるが,一人でやってたら気づけなかったかもしれないし,悩ましいですね.これも実力です.及ばなかった.

今回はボトルネックが 帯域 → (静的ファイルのキャッシュ) → CPU → (インデックスを貼る) → (N+1 修正) →メモリ → (複数台構成) → メモリ (!!!) と前回よりは進めたと思っていますが,メモリバウンドになったときにどのエンドポイントがそうさせているのか,アプリまるごと複数台にコピーするんではなくエンドポイント単位で複数台構成にするアイデアは思いついても良かったかなという感じですね.ISUCON やパフォーマンスチューニングにおいては推測よりも計測が大事と言われますが,単に計測をすれば良いのではなく,それを細かい粒度で行うことも重要であることを痛感しました.今回の例でいうと,複数台に増やすのも単にアプリケーション全体のメモリが足りないからではなく,もう少し対象を絞って,(このエンドポイントはアクセスが少ない割に重すぎるのでこれだけ移すなど) 具体的な根拠を伴ってできれば良いスコアに近づけたのかなと思っています.

最後に

このメンバーで出るのは残念ながら今年で最後で,2 年間 ISUCON を通して様々な勉強をさせていただきました.ありがとうございました.また今年は Wantedly のオフィスの一室をお借りして参加させていただきました.ホワイトボードや空調,ディスプレイやスクリーンなどの快適な環境を提供いただきとても感謝しています.

あと今年の ISUCON はシステムがすごくて,チームでひとつベンチマーカが存在していてキューがサクサクだったのと,例年の定石が通用しにくい超良い問題設定や,そこそこ重量がある実装と,あらゆる点で前回よりもパワーアップしていて解いていてとてもおもしろかったです.ISUCON はとても楽しくコンピュータの勉強ができる機会なので皆さん是非参加しましょう. 僕は今年は残念ながら本戦には参加できないので,来年の ISUCON に向けてアップを始めます.次は勝ちに行きます.


  1. Ansible Playbook は初挑戦だったが大変に冗長なコードを書いてしまったので後日勉強する