つばくろぐ @takamii228

知は力なり

ISUCON10に参加した #isucon

先日行われたISUCON10に元同僚の id:int128 先生と id:translucens 先生と gosoudan2というチームで参加してきました。

isucon.net

事前準備

実はISUCON9に同じメンバーでgosoudanというチームで参加していて、このときは始めてだったので勝手が分からなかったものの無事スコアを残せてよかった、という形で終わってました。

参考順位的には594チーム中246位相当でした。

isucon.net

ISUCON10に向けては、各メンバーの事情やコロナもあって集まって練習したりということはせず、一週間くらい前から前回の振り返りをしつつ今回どういうTryをするかを話し合ってました。振り返りのKPTからは以下のようなものが上がっていました。

  • Keep
    • CDパイプラインが構築できた
    • 初参加でスコアが残せた
    • StackDriver Profilerでボトルネック分析のサイクルが回せた
  • Problem
    • 問題文の理解が不十分でスコアに影響する改善に時間がかけられなかった
    • 改善の計画や評価をうまく整理できず、行き当たりばったりになってしまった

前日のミーティングにて以下のTryをすることを決めました。

  • 問題文をまず精読してドメインをきちんと把握する
  • 最初のスコアを出す、最初の改善を出すまでにやることをリストアップしておく
  • 1時間単位で情報の同期をとる

また目標としては去年以上の順位をとること、またアルゴリズム、データベース、ネットワーク通信、インフラ構成の中から少なくとも3種類の性能改善を実現することを上げました。

利用する言語は全員Gopher道場卒業生なのでもちろんGoです。

当日スムーズに動けるように、競技が開始してからやることをTo DoリストにしてGoogle Docsで共有しておきました。また当日も各メンバーが気づいたことわかったことをGoogle Docsに集約する形ですすめることにしました。また競技中のコミュニケーションはZoomを繋ぎっぱなしにしてSlackでテキストコミュニケーションを取ることにしました。

当日の流れ

当日は開始が遅れて12時20からの開始になりましたが、事前に昼食を済ませて待機していました。

時系列でやったことを並べると以下のような試合展開でした。

  • 12時 ~ 13時台
    • 問題文の精読を各メンバーで実施し20分個人作業、15分共有のサイクルを回す
    • sshの設定を全員で共有し全員各サーバにsshできることを確認
    • サーバー構成を確認して上がっているプロセスや動いているアプリケーションの状況を確認
    • 標準構成でスコアを取りに行った => 13:15分ごろに初回ベンチ実行して499
    • ソースコードGitHubにコピー
    • インフラ系の設定ファイルをあとでロールバックできるようにバックアップを作成
    • メトリクス計測できるようにStack Driverの設定を実施
    • GitHub ActionsでSelf Hosted Runnerを使ったCDパイプラインの構築に着手
    • 業務シーケンスのわかったことを共有
  • 14時台
    • GitHub Actionを使ったCDパイプラインが出来上がる
    • 各画面から呼ばれるAPIマッピングを把握、改善できそうな処理にあたりを付ける
    • DBのperformance_profileを設定
    • AP2台構成、DB1台構成にして不要なプロセスを停止してProfileをオンにして2回目のベンチ => 322
    • DBのCPUが100%で張り付いててAPはすっかすか、DBにindexなし、nazotteのAPIコールが遅いことが判明
    • Stack Driverのプロファイルのオン・オフを環境変数で切り替えるように修正
  • 15時-16時台
    • DBにindexを付与
    • nginxのログにレスポンスタイムを追加、変なログが無いか確認
    • ベンチを回す => 683に向上
    • 検索画面でconditionsで毎回jsonファイルを読んでることに気づくもProfilerみてもそんなに負荷がかかってないので放置
    • nazotteのN+1にトライ開始
    • nginxのbot排除のフィルター処理を追加
    • APIの処理概要をSQL単位で精読
  • 17時台-18時台
    • nazotteのN+1とbotの排除でスコアが1350に
    • buffer_sizeのwarningが出てたので拡張するように修正
    • select * 部分を最適化しようとクエリのリストアップを開始
    • MySQLを8に上げたらどうなるかトライ開始
  • 19時台
    • MySQLを8にしたらスコアが激減、conf設定をいじり始める
    • いじってもスコアが改善しないのでMySQL5.6に切り戻す
    • select *を変えると初回チェックで弾かれるのではと思い断念
    • Topの low_priced にpriorityやstockのORDERをつけたらスコアが伸びるのではとトライ開始
    • データ登録のInsertをbulk insertに変更するように修正
    • featureの文字列カンマ結合のLIKE検索が重そうなのでTABLE追加に着手
  • 20時台
    • low_pricedの修正を入れたらレスポンス不正でアウトだったので断念
    • bulk insertの修正が入ってスコアが1472に
    • featureのTABLE追加はレスポンス不正の不具合が取れず断念
    • bulk insertのバージョンでサーバーにデプロイして再起動テストに備えて設定を最終確認

私がアプリの深い仕様理解やスコア改善に効果がありそうな改善のリストアップを、 id:translucens 先生がプロファイル設定やDB周り改善の実施、id:int128先生がデプロイパイプライン含めた開発の下回り整備とGoのアプリ実装という役割分担でうまく3人で協力しながら立ち回れたかなと思います。

スコア推移

サブミットしたスコアの推移は以下の通りでした。最終的な参考順位は1399で92位 / 468チームだったようです。nazotteの改善ができたあたりでは途中は30位内くらいだった気がしますが、そこからスコアが伸びなかったのが悔やまれます。

f:id:takamii228:20200915093319p:plain

isucon.net

振り返り

前回は初回参加で右も左も分からなかったですが、前回の反省を踏まえた改善アクションも取れましたし、ある程度の性能改善アクションも取れてスコアも伸ばすことができました。

競技終了後の振り返りでは事前準備がうまくいったこと、tag pushによるGitHub ActionのCDパイプラインができたこと、問題を十分理解できたことなど前回の反省が生かされたKeepが上がりました。一方でAP2台+DB1台の構成に固執してたねってのが上がって、事前に想定してないアクションはなかなか本番ではとれないなと感じました。

個人的にはGoを1年以上まともに書いてなかったので、アプリの改善を自信を持って書けなかったのは悔しかったです。でも業務理解やタイムキーパー、nginxの設定等でチームには貢献できたかなと思います。

来年もISUCONがあるかわからないですが、3回目は機会があれば本戦出場を目指して戦えたらいいなと思います。参加した皆さん、運営の皆さん本当にお疲れさまでした!!!