なになれ

IT系のことを記録していきます。

ISUCON11予選に参加した

8月21日(土)に開催されたISUCON11予選に参加しました。ISUCONへの参加はISUCON9の参加以来、2年ぶりになります。

isucon.net

今回は会社の同僚と3人チームで参加しました。私以外の他2名はISUCON初参加というメンバー構成でした。
結果は予選敗退という形でしたが、ISUCON11予選自体は問題の内容のクオリティが高く、非常にやりごたえのある内容でした。
今後の反省も踏まえて、ISUCON11予選の参加記録を残しておきたいと思います。

事前準備

社内では、Node.jsをよく活用しており、Node.js実装で臨むことを決めていました。
自分の役割としては、DevOps的なポジションを担当しました。
デプロイスクリプトの実装やパフォーマンス計測のスクリプト実装などに取り組む役割です。
このあたりは、事前にある程度想定して、スクリプトのサンプルを用意しておきました。
具体的には、デプロイを行うためにGitリポジトリからPullを行い、systemctl上のnode.jsのサービスを再起動してデプロイを行うスクリプトを用意しておきました。
また、alpを使って出力したnginxのアクセスログ結果やpt-query-digestの結果を書き込んだhtmlファイルを用意し、nginx上に配置して、ブラウザから確認できるスクリプトを用意していました。
New RelicのインフラやAPMを利用できる手順も用意していました。

予選の数日前にチームメンバーと合同で最初の1時間の動きを実際に環境を用意して確認する会も実施し、ある程度事前の準備をしたつもりでした。

本番

自分のメイン作業としては、他メンバーの作業を効率化する仕掛けの導入です。
パフォーマンスチューニングは他メンバーに任せていました。

やったこと

自分がやったこと

  • サーバ上のプログラム、設定ファイルのGit管理
  • SSH Config Fileの作成
  • デプロイスクリプトの作成
  • nginx、mysqlのログを計測するためのスクリプトの作成
  • New Relicのインフラ、APMの導入
  • 複数台へのデプロイスクリプトの作成
  • GET /api/isuのN+1問題の解消(修正できず

チーム全体でやったこと

  • アプリケーション2台、DB1台で動くように複数台構成にした
  • isu_conditionテーブルへのINDEX追加
  • POST /api/conditionのN+1問題の解消
  • Redisの導入(アプリケーションでは結局使えなかった

複数台構成、INDEXの追加、N+1問題の解消でスコアが伸びて、最終的に2万点台ほどのスコアで終了しました。

わかったこと

事前には、ある程度準備をしてきたつもりですが、実際に本番になると色々戸惑うことがありました。
ISUCON11では、MySQLではなく、MariaDBが採用されており、事前に用意していたスクリプトの内容を若干見直す必要がありました。
具体的には、設定ファイルのディレクトリパスが異なっていました。

デプロイスクリプトに関して、ISUCON11のNode.js実装はTypeScript化されていましたが、事前に用意したデプロイスクリプトは素のNode.jsで動作する前提でした。
事前に用意したスクリプトで完成したと思い込んでいましたが、実際にはTypeScriptのビルドが実行されずにアプリケーションが更新されていない状態になってしまいました。
アプリケーションの実装を少し見ていれば気づけるものでしたが、事前に決めた作業の段取りに沿って作業した結果、気づけませんでした。 ログ上はビルドがなされていなくても前回の状態で正常に動いているように見えていたのも気付くのが遅れた要因でした。
アプリケーションの実装を確認して、デプロイスクリプトをカスタマイズする段取りが必要でした。

nginx上にhtmlファイルを配置するやり方があまりわかっていなかったため、手間取りました。
具体的には、rootディレクティブの挙動が分かっていませんでした。
ISUCON11の設定の場合、以下のように/パスでアプリケーションへ向けられていました。

    location / {
        proxy_set_header Host $http_host;
        proxy_pass http://127.0.0.1:3000;
    }

ここからhtmlなどのドキュメントを特定のパスで公開する設定に手間取りました。
事前の想定では、/apiなどの一階層下りた形でアプリケーションへ向けられていることを想定していたためです。
このあたりは最終的に以下のように実施することで設定できましたが、時間がかかりました。

    location /log/ {
        root /home/isucon/webapp/public;
    }

/home/ISUCON/webapp/publicにlogディレクトリを作成し、そこにhtmlファイルを配置する形です。
また、rootディレクティブはrootに指定したパス+URIパスでホスト上のファイルを参照しにいくという挙動が分かっていませんでした。
rootディレクティブで指定したパスでファイルを見にいくものと勘違いしていました。このような挙動を行う場合、aliasディレクティブを使うことをあとから知りました。
Git管理からこのあたりの計測系の実装を行うまでで、2時間ほどの時間を費やしてしまい、タイムロスが大きかったと思います。

複数台構成の設定漏れで、意図しない挙動が発生して、トラブルシューティングに時間がかかることがありました。
アプリケーションのホストからDBのホストに向き先を設定する中で、当初アプリケーションロジックのみDBの向き先を変更していて、アプリケーションから実行されるDBの初期化処理ではDBの向き先を変えていなかったという事象でした。
これはアプリケーションのコードだけ修正を行い、もともと用意されていたDBのホスト名を定義した環境変数を変更していなかったことが原因でした。
全体の構成を把握できていないままに局所的に修正をしてしまったことがトラブルにつながりました。これは普段の業務でもありそうなミスで、さもありなんという感じでした。

複数台構成の情報連携がうまく取れておらず、2台目のサーバが全くアプリケーションの更新がなされていない状態がありました。
その問題点に気づかず、ベンチマークがなぜかfailするというトラブルシューティングに時間を費やしました。
これは2台のサーバのうちのどちらかでDBの初期化処理が走ることになり、どちらのサーバでも処理が動作するようにセットアップがなされているべきだったのですが、それがうまくできていませんでした。
このあたりは複数台構成によって、どのようなリスクがあるのかを把握できていなかったことが原因と考えられます。また、早めに複数台に対応したデプロイスクリプトを作成しておくべきだったと思います。
複数台構成に時間が取られてしまい、本格的にアプリケーションのチューニングに取り組めたのが開始から4時間ほど経ってからという状態で遅すぎました。
また、複数台構成のトラブルシューティングに追われ、まともな計測結果の共有が遅れることにもなってしまいました。

New RelicのAPMに関しては、単純に仕掛けるだけだと、DBのトレーシングができませんでした。APIの計測結果が見れるだけであまり役立ちませんでした。
このあたりはアプリケーションでどのようなモジュールを利用しているかで、APMで取得可能な情報が違ってくるため、単純に導入するのではなく、もう少し考える必要があったかと思います。

N+1問題を認識していたのですが、自分のNode.js力が足りずに1時間ほどの残り時間で修正することができませんでした。
このあたりはオブジェクトや配列を思うようにNode.jsで扱えるようにならないといけないと感じました。

まとめ

事前の予習ではそれなりにやったつもりでしたが、いざ本番になるとさまざまなところで時間がかかってしまいました。このあたりは経験が必要でした。
競技時間の8時間はあっという間で、ISUCONは正に競技だと感じました。このような経験も個人的には良い経験でした。
ISUCON11運営の皆様、このような機会を提供して頂き、ありがとうございました!