[AWS] RDSがなんかやたら遅い時に確認すること

Kenji
Kenji

Engineer / 合同会社irori

公開日
カテゴリ
AWS・インフラ
AWS
RDS

こんにちは。

今回は、原因不明で、突如なんかやたらRDSが重くなったときのことを話します。

早速主題

原因は、gp2のBurstBalanceが死んだことでした。

ここからは、発生当日に残したメモを整理しつつ流れを振り返ります。


何が起きてたか(現場メモ)

  • 現象:ECSのデプロイ後にアプリが500系エラーを連発
  • ログ:コンテナの entrypoint で実行するDBスキーマ変更(マイグレーション)がタイムアウトで落ちる
  • RDS:BurstBalance が 0% に張り付き、I/O がベースラインまで絞られて激遅
  • 背景:ちょうど同じタイミングで 定期バッチ が走っており、I/O を食い散らかしていた疑い

つまり「I/O が出ない状態で重い DDL/マイグレーションを踏んだ → タイムアウト → 起動失敗 → 500」というシンプルな流れでした。


まずやったこと(時系列)

  1. ECSのタスクログをチェック
    → entrypoint 内のスキーマ変更がタイムアウトで落ちていることを確認
  2. CloudWatch の RDS メトリクスを確認
    → BurstBalance は 0%、DiskQueueDepth は盛り盛り、Read/WriteIOPS はベースラインで頭打ち
  3. 「これはクレジット枯渇だ」と判断
    → アプリのバグではなく DB I/O の詰まりが主因と確信
  4. RDS ストレージを一時的に gp3 へ切り替え
    → 体感 10分程度で復旧(500 が止まり、マイグレーションも完走)

超ざっくり:BurstBalanceって何?

gp2 は容量に応じた ベースライン IOPS が決まっていて、短期的には バーストで速くできる仕組みです。ただしクレジットは有限で、使い切ると急にベースラインへ落ちる。

普段は気づきにくいのですが、バッチ + デプロイ(DDL) のように I/O の山が重なると一気に枯れます。今回はまさにその瞬間に重い DDL が刺さった形です。


なんで 500 になったの?

  • コンテナ起動時(entrypoint)で DDL/マイグレーション を走らせている
  • その瞬間、RDS が I/O を絞られた低速モード(Burst 0%)に突入
  • DDL が待ち行列に積まれて時間切れ → entrypoint 失敗 → コンテナ不健康 → 500

「アプリが悪い」というより「環境が DDL を許さないタイミングに当たった」が実態でした。


対応:とりあえず gp3 に

  • gp3 は容量に依存せず 一定の IOPS/スループット を確保できるので、「クレジット枯渇で急降下」がありません。
  • 今回は一時的に gp3 にスイッチ → 約 10 分で回復。
    以後 500 は消え、マイグレーションも完了。

余談:コスト的にも gp3 は悪くないので、そのまま gp3 運用でも十分アリだと思っています。


なぜ 10 分で戻った?(個人の推測)

  • ストレージタイプ変更の適用で I/O の頭打ちが解消
  • 直近の I/O 山場(バッチ)が終わり、待ち行列が掃けた
  • アプリはリトライ/再起動で自然回復ラインに乗った

要は「I/O を出せる状態に戻す」が一番効いた、という感触です。


次回の自分へのメモ(再発防止)

運用系

  • CloudWatch アラーム
    • BurstBalance < 50% で通知
    • DiskQueueDepth、FreeStorageSpace、Read/WriteLatency も閾値設定
  • バッチのスケジューリング見直し
    • デプロイ時間とかぶらせない
    • 大量処理は分割 or レプリカで読む
  • 可能なら常時 gp3。
    • 「静かな時は爆速、混むと地獄」の振れ幅をなくす

アプリ/DB系

  • エントリポイントで重い DDL を叩かない(段階適用・メンテ時間を設ける・リトライ/バックオフを設計)
  • マイグレーションは
    • ロック時間が短い手順に分ける
    • インデックス追加は CONCURRENTLY 相当(MySQL はやり方に注意)
    • 長時間フルスキャンが走る変更は事前検証を徹底

最後の切り札

  • gp2 を続けるなら、容量を増やしてベースライン IOPS を底上げ(コストとのトレードオフ)

まとめ

  • 症状:デプロイ後に 500 連発 → 実はDB I/O が枯渇
  • 原因:gp2 の BurstBalance 0%(バッチとタイミングが悪かった)
  • 対応:gp3 に切り替え → 体感 10 分で回復
  • 教訓:I/O の山が重なる設計は避ける。監視とアラートを早めに仕込む。重い DDL は踏むタイミングと手順を慎重に。

この辺りをテンプレ化しておけば、次に「なんか急に RDS が重い…」が来ても落ち着いて捌けるはずです。

この記事を書いた人

Kenji
Kenji(Engineer)

合同会社iroriのエンジニア。Rails / Next.js / AWS を中心とした受託開発と、生成AIを使った開発フローの整備を担当しています。このブログでは、実際に自分の環境で試した手順や、詰まったポイントと解決までの記録を書いています。

Related Posts

[AWS] GenU(Generative AI Use Cases JP)でAWS × 生成AI入門してみた

[AWS] GenU(Generative AI Use Cases JP)でAWS × 生成AI入門してみた

[AWS] AWS CDKでNext.jsのSSGでCloudFrontとS3にデプロイする

[AWS] AWS CDKでNext.jsのSSGでCloudFrontとS3にデプロイする