🪑

ISUCON14振り返り?

2025/03/28に公開

記事の概要・想定読者

  • ISUCONやウェブパフォーマンスチューニングに興味があるエンジニア
  • 競技準備に役立つ情報を求めている方

ISUCONとは

  • ISUCON(Iikanjini Speed Up Contest)は、LineYahooが2011年から開催されている日本最大級のウェブパフォーマンスチューニングの競技大会です。

主な特徴

  • 高速化を競う

    参加者は与えられたウェブサービスを、規定に基づいて限界まで高速化し、スコアをランキング形式で競うチーム戦です。

  • 幅広い技術領域

    インフラ、ミドルウェア、データベース、アプリケーションコードなど、さまざまな技術分野に触れることができます。

  • スキル向上に最適

    実践的な課題を通じて、ウェブパフォーマンスの最適化技術を習得できるため、エンジニアに人気があります。

ISUCON14のお題

ISUCON14のお題については、以下から詳細を確認できます

https://youtu.be/UFlcAUvWvrY

https://github.com/isucon/isucon14

メンバー

チーム「ハリー・ポッターと賢者のEC2」として参加、
普段から勉強会を一緒に開催しているメンバーで構成されています。

名前
Harumi Yamashita (私)
asamuzak
keigo

ISUCON14の目標

前回の ISUCON13 では、出場を直前に決定したため十分な準備ができず、694チーム中320位という結果に終わりました。

この反省を踏まえ、今年の ISUCON14 に向けては事前に十分な準備を行い、目標を明確に定めることにしました。

■ 目標設定の根拠

チーム内で 過去のISUCONのスコアと順位のヒストグラム を作成し議論を行い、過去の傾向を分析しました。

ISUCONは回によってスコア分布や難易度が大きく変動するため、絶対スコアではなく相対順位で目標を設定する方が妥当と判断。

その結果、ISUCON14では上位25%以内を目指すことに決定しました。

ISUCON14への取り組み

ISUCON14で目標を達成するために、私たちのチームでは以下の対策を実施しました。

■ 過去問への取り組み

まずは個人で過去問に取り組み、出題傾向や競技の全体像を把握しました。その後、チームで協力して問題を解く演習を複数回行い、連携力を高めました。

使用したのは matsuu/aws-isucon の環境で、特に private-isu、ISUCON11~13 といった比較的新しい問題を中心に解きました。これらの問題は設計や構成がより洗練されており、最近の出題傾向に即していると考えたからです。

■ 手順書・ドキュメントの整備

競技開始直後に環境構築に手間取らないよう、開発環境やDB、ミドルウェアのセットアップ手順を事前にドキュメント化しました。

この整備により、ISUCON13と比較して初動にかかる時間を大幅に短縮でき、その分パフォーマンスチューニングに集中することができました。

■ 役割分担の明確化

各メンバーが担当分野を持ち、それぞれが主体的に動けるようにしました。

これによりチーム全体の対応力と問題解決速度が向上し、効率よくボトルネックの特定と改善を進めることができました。

ISUCON14の結果

その結果、スコア13,907点で843チーム中85位という結果を出し、目標を達成することができました。

詳細な結果はこちらからご覧いただけます。

測定ツール紹介

最適化の名言に**「推測するな、計測せよ」**とあるとおり、闇雲に重そうに見えるところを改善しても実際のボトルネックを改善し最適化できる可能性は低いです。
Isuconでも計測ツールを使用し最適化計画を立て的確にボトルネックを解消していくことが大切です。

下記はisuconで一般的に使用されているツールです。

他にもdstat、pproteinなどのツールがありますが自分たちは以下のモノを使用しました。

pt-query-digest

実行に長い時間がかかっているクエリを集計し、最適化の候補となるクエリを見つけるために使用しました。

公式ドキュメント 使用方法

alp(Access Log Profiler)

nginxのアクセスログの集計ツール。
実行に長い時間がかかっているクエリを集計し、最適化の候補となるクエリを見つけるために使用しました。

https://github.com/tkuchiki/alp

公式ドキュメント 使用方法

pprof

パフォーマンスのボトルネックを可視化するために使用しました。

公式ドキュメント 使用方法

事前準備

競技を始めるにあたっては、開発環境やDB、ミドルウェアのセットアップを最初に済ませておく必要があります。

今回私たちのチームはセットアップをドキュメント化し、確実かつ素早く行えるようにしました。

このことで前回のISUCON13に比べて大幅に時間を節約でき、パフォーマンスチューニングに注力することができました。

make file

Makefileを作成することで、頻繁に使用する複雑なコマンドや一連の操作を簡素化し、効率的に実行できるようにしました。

コマンド一覧

  • help: 利用可能なMakeコマンド一覧を表示
  • nginx: NGINXのログを初期化して再起動
  • mysql: MySQLのログを初期化して再起動
  • go: アプリケーションをビルドして再起動
  • restart: NGINXおよびアプリケーションをまとめて再起動
  • pt-q: MySQLのスロークエリログを分析
  • alp: アクセスログを解析ツールで可視化
  • pprof: プロファイラを使って性能解析結果を表示

Notionの活用

大会に向けてNotionに専用ページを作成し、情報を集約することで作業効率の向上を図りました。

手順書の整備

DB、NGINX、GitHubなどのセットアップ手順を事前にドキュメント化し、役割分担して実行することで、大幅な作業時間の短縮に繋がりました。

主要なコマンド・設定の一覧

チューニング中によく使うコマンドや、アプリケーション・DBに関する設定を一覧化することで、必要な情報にすぐアクセスでき、作業の効率が向上しました。

作業トラッキング用テーブル

各メンバーの作業状況をテーブル形式で可視化することで、全員が互いのタスクを把握しやすくなり、意思疎通の円滑化、助け合いやレビューの促進に繋がりました。

image.png

マニュアルの重要な点へのリンク

何度も参照する可能性のある資料やマニュアルをリンクでまとめることで、チーム内での情報共有がスムーズになり、検索や確認の手間を省くことができました。

本番で改善できたこと

  • DB
    • インデックス
    • DB分散
  • Code base
    • ridesのバルク取得
    • キャッシュ

当日のタイムスケジュール

競技前(8:30~10:00)

本番ではメンバーの家を借りてオフラインで準備を行いました。これにより、迅速な意思疎通と意思決定が可能となりました。
朝は、メンバーの奥さんにおいしい朝ご飯を作ってもらい気合も十分。

AWSにwebサービスの環境を構築(10:00~10:15)

CloudFormationを使ってWebサービスの環境をAWS上に構築し、ベンチマークを回して初期点数を確認しました。

ドキュメント読み(10:00~10:15)

AWSの構築を担当しないメンバーはすぐにお題のドキュメントを読み込み、アプリケーションの全体像や大会のルールを把握しました。

今回はパフォーマンスだけでなくユーザー満足度にも重点が置かれていたため、ドキュメントの理解がより重要でした。

各セットアップ(10:15~10:50)

競技環境のセットアップは、事前に役割分担とドキュメント整理を行っていたおかげで、昨年に比べ大幅に時間を短縮できました。具体的には次の作業を行いました。

  • GitHubへのリポジトリ登録
  • MySQLの初期設定
  • Nginxの初期設定
  • Memcachedの設定
  • pprofの設定

チューニング開始

特に印象に残ったところ

10:50~11:30

まずベンチマークを回し、各計測ツールから改善点を探しました。初期段階では練習でしていたように役割分担を行い、各メンバーが改善を進めました。

インデックス[2647点]

pt-query-digestを使用して、実行時間の長いクエリを特定し、インデックスを最適化しました。

サーバー分散

アプリケーションサーバーとDBサーバーの分離を試みましたが、データの不整合が発生し失敗しました。原因は、後で判明しました。

N+1

alpやpprofを用いてボトルネックとなっているエンドポイント・関数を確認。
重い上位のエンドポイントを確認するが特出した重いコードは見当たらない、

11:30~13:30[2828点]

データベースからのタイムスタンプ取得を廃止、バルクフェッチやバルクインサートを導入しN+1問題の解消。
更に、エンドポイントがあまり頻繁に叩かれておらず、ユーザー満足度への寄与も少ないことに目を付けownerGetChairsを3秒キャッシュ

測定ツールでは負荷が下がっていることを確認しましたが、スコアの上昇は限定的でした。

中々点数が上がらなくやきもき

13:30~17:00

Indexの張り直し

改善が進んだため、新たな重いクエリがqt-query-digestの上位に浮上。
インデックスを張り直し点数が上がるが

各エンドポイントのキャッシュ化

特にN+1問題が見当たらなかったため、重い処理をキャッシュ化しました。これにより、レスポンスタイムの改善を図りました。

N+1の解消(Yamashita)

/api/app/rideエンドポイントでrユーザーのrideを全て獲得した後にfor loop内でフィルターをしている部分を改善

  • DBから取得するデータ数が減少
  • for loop回数の減少

<改善前>

rides := []Ride{}
if err := tx.SelectContext(
	ctx,
	&rides,
	`SELECT * FROM rides WHERE user_id = ? ORDER BY created_at DESC`,
	user.ID,
); err != nil {
	writeError(w, http.StatusInternalServerError, err)
	return
}

items := []getAppRidesResponseItem{}
for _, ride := range rides {
	status, err := getLatestRideStatus(ctx, tx, ride.ID)
	if err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}
	if status != "COMPLETED" {
		continue
	}

<改善後>

	if err := tx.SelectContext(
		ctx,
		&rides,
		`SELECT *
		 FROM rides
		 WHERE user_id = ?
		   AND (
			 SELECT rs.status
			 FROM ride_statuses rs
			 WHERE rs.ride_id = rides.id
			 ORDER BY rs.created_at DESC
			 LIMIT 1
		   ) = 'COMPLETED'
		 ORDER BY created_at DESC`,
		user.ID,
	); err != nil {
		writeError(w, http.StatusInternalServerError, err)
		return
	}

17:00~17:30

DBサーバー分散の成功

isuride-matcherという別サービスが動作しており、サーバー分散時に両方のインスタンスで動いていると不整合を起こしてしまうことを突き止め、DBサーバーでは停止して再度サーバー分散を行った[8246点]
点数が大幅に上がりメンバーの鼻息が荒くなる

rideのマッチング間隔の調整

isuride-matcherによってのユーザーとisuのマッチング間隔を短くしたところ、ボトルネックが少なくなってきたこともあり大幅に点数が上がる

pprofの削除

17:30~18:00

競技環境のチャックなど再試験で落ちないための確認を行って、少し早めに作業終了。

反省点

セットアップの自動化

高順位のチームの戦い方を見ると環境のセットアップの自動化に力を入れていることが分かった。
なので自分たちのチームでもansibleを導入し、以下の項目を自動化する予定です:

  • インフラ設定の自動化
  • Git管理の自動化
  • ISUCONのベンチマーク結果の自動収集・可視化
  • 各ログ(MySQL、Nginx、Go)の自動収集・可視化

!載せる??(載せるなら別記事かもっと目立つとこ?

https://github.com/Harry-Pointer/isucon-provisioning

ドキュメントの読み込み

ドキュメントの読み込みが甘く、ユーザー満足度に寄与する改善を後回しにしてしまった。
今後さらなる高順位を目指すうえでパフォーマンスチューニング+αにも気を使わないといけない。

  • アプリケーションはどこまで理解して作業すべきか考えたい

トリガーの使用

今回使いまわせるようなトリガーを設定するのに不整合が起こり苦戦してしまった。
再利用性を加味せず、素早く必要なユースケースごとに単純化したカラムを追加するような作戦を考慮するべきかもしれない。

コードレビュー

特に後半になると時間が無くコードレビューを行う時間が取れない/勿体なくなったので、github actionを用いてタイポや明らかな問題点などはgptのレビューを入れることも検討したい

!出来なかった事

matchingのロジック改善

キャッシュ3秒できると書いてあるが、短くしないと不整合起きるの気が付いたが上手くいかず外したエンドポイントがあった。

AWSのエラー毎回起きる

振り返り

ISUCONで勝つためのISSUE分析

次回は30位入賞を目指し、ISUCONの勉強とともにソフトウェアエンジニアとしての成長も目指します。

その目標を達成するため、次のISUCONに向けてISSUE分析を行いました。

  • 30位入賞のための4つのメインISUUEs

パフォーマンス改善の知識や戦略

ISUCONの最大の鍵は、限られた時間内でどれだけパフォーマンスを最適化できるかです。

ベンチマーカーの仕様を正しく理解し、よく使われる改善手法やGo・SQLのチューニング技術を身につけることで、ボトルネックを素早く特定・修正できるようにする必要があると考えました。

実装力

ISUCONは限られた時間内に大規模な修正を行い、エラーや障害が起きたらすぐに原因を突き止める必要があります。

そのため、言語スキル・ツールやサーバーの操作・設計力といった要素を総合的に高めることで、より安定した改善サイクルを回せるようになると考えました。

ツール/環境の充実

Ansibleを用いた環境構築の自動化を進め、短時間で最適なセットアップができるようにしたいと考えています。

チームの連携力

今回はオフラインで横並びの席に着き、タイムテーブルなどを活用してタスク管理を行ったため、チーム内の連携に大きな問題は見られませんでした。次回の ISUCON15 に向けて、引き続き一緒に勉強を重ね、連携力にさらに磨きをかけていきたいと考えています。

まとめ

Isucon14ではベンチマーカーが非常に安定しており、ほとんど待ち時間なく検証を回せたおかげで、迅速に改善を繰り返せました。

エラー文もわかりやすく、調整ポイントの把握がしやすかったのでパフォーマンスチューニングに専念できで大変助かりました。

運営の皆様、本当にありがとうございました。

また、今年のISUCON14では、チームで協力しながら楽しく取り組めたのが大きな収穫でした。とりわけ、DBを分散させて大幅にパフォーマンスが向上したときなど、ISUCONならではの「改善する楽しみ」を存分に味わえて本当に良かったです。

今後もチーム全員で切磋琢磨し、来年のISUCONではさらに上位を目指して挑戦していきたいと思います。

Discussion