メインコンテンツにスキップ

APIを1.7秒から47%高速化!僕らが実践した、データで語るパフォーマンス改善術

タグ: 🏷 AWS ,Lambda ,Golang ,React

ちょっとしたお知らせ 実はこの記事、ほとんどAIに書いてもらいました。性能改善自体もAIに依頼して進めた記録を元に作成しています。Markdownの形式が合わない部分など、ごく一部の形式的な修正だけ僕が手を入れています。

背景

アプリケーション開発をしていると、「なんか重いな」「もう少し早くならないかな」といった感覚的な問題にぶつかること、よくありますよね。でも、いざ改善しようとすると、何から手をつけていいか分からず、闇雲な対応になりがちです。

  • 何が遅いのかわからない(フロントエンド?バックエンド?ネットワーク?)
  • 改善策の効果が見えない(本当に早くなったのか?)
  • 根本解決ではない(一時的には早くなったが、また遅くなる)

僕たちのプロジェクトでも、**「ログインボタンを押してから画面が表示されるまで約1.7秒もかかる」**という、ユーザー体験として看過できない問題がありました。しかし、科学的アプローチ(測定→分析→仮説→実装→検証のサイクル)を徹底的に採用した結果、47%もの大幅改善を達成できたんです。

この記事では、感覚ではなくデータに基づいたパフォーマンス改善手法を、実際の測定データと改善コードを交えながら、詳しくご紹介していきたいと思います。

科学的アプローチとは?

パフォーマンス改善は、医者が患者を診断するプロセスとよく似ています。

従来の「感覚的」アプローチの問題点

これは、患者をろくに診察もせずに「疲れてるみたいだから、とりあえずこの薬でも飲んでみて」と、勘で薬を処方するようなものですよね。

❌ 感覚的アプローチ:
「遅い気がする」
↓
「とりあえずメモリを増やそう」(とりあえず栄養ドリンクを処方)
↓
「まだ遅い」
↓
「キャッシュを入れよう」(とりあえず別の薬を処方)
↓
「あまり変わらない...」(治らない)

科学的アプローチのサイクル

一方、科学的アプローチは、まさに腕の良い医者が患者を診断していくプロセスそのものです。

✅ 科学的アプローチ(医者の診断プロセス):
1. 🔍 測定 (Measure) → 問診・体温測定・血圧測定
   → 現状を正確に把握

2. 📊 分析 (Analyze)  → 検査結果から原因を特定
   → ボトルネック(根本原因)の特定

3. 💡 仮説 (Hypothesize) → 病名を推測し、治療計画を立てる
   → 改善策の立案

4. 🛠 実装 (Implement) → 薬の処方・治療の実施
   → 対策の実行

5. ✅ 検証 (Validate) → 再検査で効果を確認
   → 効果の確認

6. 🔄 繰り返し → 完治まで、または健康維持のために
   → 継続的改善

このサイクルを回すことで、的確に問題を解決できます。

Phase 1: 測定(Measure) - 現状把握

医者の診断でいう「問診・検査」の段階です。

まず、ユーザーがログインボタンを押してから、情報が表示されるまでの全工程(エンドツーエンド)の時間を詳細に分解しました。

🕐 エンドツーエンド測定結果: 1,675.7ms(約1.7秒)

詳細内訳:
├─ 🔐 ログイン処理: 1,591.3ms (95.0%) ← 最大ボトルネック
│   └─ 🚨 サーバー処理: 767ms (45.8%) ← 核心問題
│       ├─ Lambda Cold Start: ~400ms (推定)
│       ├─ Cognito認証処理: ~250ms (推定)
│       └─ レスポンス生成: ~117ms
├─ 📡 ユーザー情報取得: 512ms (30.5%) ← 二次ボトルネック
└─ ...その他

測定ツールと実装

バックエンド測定(Go Lambda関数)

// loginHandler関数の中で、各処理のポイントで時間を記録する
func loginHandler(...) {
    monitor := monitoring.NewEnhancedPerformanceMonitor()
    
    // チェックポイント1: ハンドラ開始
    monitor.RecordCheckpoint("handler_start")
    
    // チェックポイント2: Cognitoクライアント初期化完了
    client, err := getCognitoClient()
    monitor.RecordCheckpoint("cognito_client_ready")
    
    // チェックポイント3: 認証完了
    result, err := client.InitiateAuth(...)
    monitor.RecordCheckpoint("cognito_auth_complete")
}

フロントエンド測定(React + TypeScript)

// ログイン処理の中で、各ステップの時間を計測
const handleLogin = async (email, password) => {
    // 全体フローの計測開始
    const totalMeasurement = startMeasurement('total_login_flow');
    
    // API呼び出しの計測開始
    const loginMeasurement = startMeasurement('login_api_call');
    await authAPI.login(email, password);
    loginMeasurement.end(); // 計測終了
    
    totalMeasurement.end(); // 全体フローの計測終了
};

ネットワーク測定(curl)

curlとは? コマンドラインからWebサーバーにリクエストを送れるツールです。ブラウザを使わずにAPIの動作確認ができます。

# curlコマンドでAPIのネットワーク通信にかかる時間を詳細に計測
# 出力例:
# time_namelookup:    0.010s  ← ドメイン名からIPアドレスを調べる時間
# time_connect:       0.026s  ← サーバーに接続するまでの時間
# time_appconnect:    0.090s  ← 暗号化通信(SSL/TLS)の確立にかかる時間
# time_starttransfer: 0.857s  ← リクエストを送信してから最初の1バイトが返ってくるまでの時間(サーバーの処理時間)
# time_total:         0.857s  ← 総時間

Phase 2: 分析(Analyze) - ボトルネックの特定

医者の診断でいう「検査結果から原因を特定する」段階です。

パレート分析(80-20の法則)

パレート分析とは? 「結果の80%は、全体の20%の原因が生み出している」という考え方。パフォーマンス問題では、ごく一部の処理が全体の遅延の大部分を占めていることが多いため、最も影響の大きい「ボトルネック」から手をつけるのが効果的です。

測定データから、影響の大きいボトルネックを特定しました。

📊 ボトルネック影響度ランキング:

🥇 1位: Lambda Cold Start(推定400ms)
🥈 2位: 順次API処理(512ms + 体感遅延)
🥉 3位: Cognito処理時間(推定250ms)

Phase 3: 仮説(Hypothesize) - 改善戦略の立案

医者の診断でいう「病名を推測し、治療計画を立てる」段階です。

各ボトルネックに対して、「こうすれば改善するはずだ」という検証可能な仮説を立てました。

仮説1: Lambda Cold Start削減
  仮説: グローバル変数での接続キャッシュにより、初期化時間を400ms削減できるはず。
  成功基準: Cold Start時間が2500ms → 600ms以下になること。

仮説2: 順次処理を並列処理に変更
  仮説: ログインと同時にユーザー情報も取得すれば、体感待機時間が減るはず。
  成功基準: 2回発生していた待機が1回になること。

Phase 4: 実装(Implement) - 改善策の実行

医者の診断でいう「薬の処方・治療の実施」の段階です。

仮説に基づき、コードの修正やインフラ設定の変更を行いました。(具体的な実装内容は他の記事で詳述しているため、ここでは割愛します)

Phase 5: 検証(Validate) - 効果測定

医者の診断でいう「再検査で効果を確認する」段階です。

改善策を実装した後、Phase 1と同じ方法で再度測定し、効果が出たかを確認します。

改善前後の詳細比較

// 改善前ベースライン
{
  "login_api": { "avg_duration_ms": 857, "max_duration_ms": 2520 },
  "get_user_api": { "avg_duration_ms": 428 }
}

// 改善後実測
{
  "login_api": { "avg_duration_ms": 452, "max_duration_ms": 519 }, // 47-79%改善 ⚡
  "get_user_api": { "avg_duration_ms": 248 } // 42%改善 ⚡
}

エンドツーエンド体感速度

改善前の体験:
  1. ログインボタンクリック
  2. 857ms待機(ローディング)
  3. ダッシュボード画面に遷移
  4. 512ms追加待機(スケルトン)← 明確な二段階待機

改善後の体験:
  1. ログインボタンクリック  
  2. 452ms待機(ローディング)
  3. ユーザー情報含みでダッシュボード表示(待機は一回だけ)

Phase 6: 継続的監視システムの構築

医者の診断でいう「退院後の健康管理」の段階です。

一度改善して終わりではなく、将来的に性能が劣化しないように、リアルタイムでパフォーマンスを監視する仕組みを構築しました。これにより、問題の兆候を早期に発見し、プロアクティブに対応できます。

学んだ教訓

  1. 測定ファーストの重要性: 感覚ではなく、常にデータに基づいて判断する。
  2. 段階的改善アプローチ: 一度にすべてを変えず、一つずつ変更して効果を測定する。
  3. ユーザー体験を最優先: 技術的な数値だけでなく、ユーザーがどう感じるかを指標にする。
  4. コストと性能のバランス: プロジェクトの状況に応じて、最適なバランスを見つける。

まとめ:なぜこの経験が重要なのか

科学的アプローチによるパフォーマンス改善を通じて、僕たちは以下の成果と方法論を確立することができました。

  • 定量的成果: API応答時間を47%短縮し、ユーザー体験を劇的に改善。
  • 方法論の確立: データに基づいた判断サイクルにより、誰でも再現可能な改善プロセスを構築。

改善実績まとめ:

  • 🚀 Login API: 857ms → 452ms(47%改善)
  • Get User API: 428ms → 248ms(42%改善)
  • 🏆 最悪ケース: 2,520ms → 519ms(79%改善)
  • 💰 コスト効率: 56%改善
  • 👥 ユーザー体験: 二段階待機 → 一段階待機