こんにちは。プロダクト開発本部の中島です。
日常業務では動画広告関連のプロダクトの開発に携わっています。
この記事は、Supershipグループ Advent Calendar 2025の 2日目の記事になります。
TL;DR
- Cloud SQL for PostgreSQL は再起動後、バッファキャッシュが空になり初回クエリが遅くなる
- pg_prewarm で事前にキャッシュを温めることで解決できる
- ただし Cloud SQL では自動実行機能が使えない
- Cloud Logging + Pub/Sub + Cloud Run Functions で再起動を検知し、自動で pg_prewarm を実行する仕組みを構築した
はじめに
ある日、普段は 10〜30ms で軽快にレスポンスを返しているエンドポイントが、突然 200ms ほどの時間を要していました。
原因を調査してみると・・・、全体的にクエリの実行時間が平均と比べ遅くなっていました。
特にボトルネックとなっていたクエリにおいては数ミリ秒で完了するはずが、100ms 近くかかっています。
クエリインサイトで確認してみると、実行時間の内訳は CPU: 4%、I/O: 96%。
ディスク I/O がボトルネックになっていました。

直近のイベントを調べると、Cloud SQL のメンテナンスによる再起動が行われていました。
他のメンテナンスのタイミングや手動による Cloud SQL 再起動では、100ms ほどクエリ実行時間がかかるケースは再現できていませんが、クエリインサイトの内訳(I/O: 96%)から、I/O 起因である可能性が高いと判断しました。
なお、100ms に達しない場合でも、再起動後はキャッシュがクリアされるため、程度の差はあれ I/O は必ず発生します。
これをきっかけに、再起動後でも初回から I/O なしで高速に応答できる状態を目指すことにしました。
再起動後が遅い理由
PostgreSQL には、ディスクから読み込んだデータをメモリ上にキャッシュする仕組みがあります。
PostgreSQL が管理する shared_buffers と、OS が管理するページキャッシュです。
一度キャッシュされたデータは、次回以降ディスク I/O なしで高速に読み出せます。
しかし、再起動やメンテナンスが行われると、これらのキャッシュはクリアされます。
その結果、再起動直後のクエリはディスクから読み直す必要があり、I/O 待ちが発生します。
これがいわゆるコールドスタート状態です。
メンテナンス時間をリクエストの少ない時間帯に調整する手もありますが、初回リクエストで I/O が発生する問題は解決しません。
解決策: pg_prewarm の導入
pg_prewarm とは
pg_prewarm は、テーブルやインデックスのデータを事前にバッファキャッシュへロードするための PostgreSQL 拡張機能です。
再起動前のキャッシュ状態を復元することで、最初のクエリから高速に応答できるようになります。
さらに、pg_prewarm には autoprewarm という自動化機能も備わっています。
shared_preload_libraries に pg_prewarm を追加すると、バックグラウンドワーカーが起動し、以下の処理を自動で行います。
- 稼働中: 定期的に共有バッファの内容を
autoprewarm.blocksファイルに記録 - 再起動後: 記録されたブロック情報を読み込み、同じデータをキャッシュに自動で再ロード
これにより、再起動後も手動操作なしでキャッシュが復元され、初回クエリから高速に応答できます。
Cloud SQL では autoprewarm が使えない
残念ながら、Cloud SQL for PostgreSQL では autoprewarm を有効にするためのフラグがサポートされていません。
Cloud SQL でサポートされているフラグ一覧を確認すると、pg_prewarm 関連のフラグが存在しないことがわかります。
この制限については Issue Tracker でも Feature Request が挙げられています。
なお、pg_prewarm 拡張自体は CREATE EXTENSION pg_prewarm で有効化でき、pg_prewarm() 関数を手動で実行することは可能です。
しかし、再起動のたびに手動実行するのは現実的ではありません。
そこで、GCP の機能を活用して再起動後に自動で pg_prewarm を実行する仕組みを作りました。
GCP上での自動実行方法
アーキテクチャ概要
Cloud SQL が再起動すると、PostgreSQL は接続可能になったタイミングで以下のログを出力します。
database system is ready to accept connections
このログをトリガーにして、pg_prewarm を実行します。
処理の流れ
- Cloud SQL 再起動 - メンテナンスや手動再起動が発生
- Cloud Logging - 再起動完了ログを検出
- Log Sink - 該当ログを Pub/Sub へ転送
- Pub/Sub Topic - 再起動イベントとして配信
- Cloud Run Functions - イベントを受け取り、pg_prewarm の実行をトリガー
Cloud Run Functions から先は、Jobをキックする、アプリケーションの特定エンドポイントを叩くなど環境に合わせた pg_prewarm を実行する処理を実装します。
これによって、Cloud SQL 再起動時に自動でウォームアップすることが可能になります。
結果
Before: pg_prewarm 導入前
Cloud SQL 再起動後の初回クエリでは、I/O が発生していました。

After: pg_prewarm 導入後
再起動後でも、初回クエリで I/O 待ちは発生しなくなりました。
※ Before の 94ms という数値自体は常に再現していたではありません。ただ、I/O は必ず発生しており、それが CPU: 100% に変わった点がポイントです。

補足
ディスクからの読み込み自体がなくなったわけではありません。
I/O が発生するタイミングが pg_prewarm 実行時に移動しています。
おわりに
Cloud SQL for PostgreSQL では autoprewarm が使えないという制限がありますが、GCP のサービスを組み合わせることで自動ウォームアップの仕組みを実現できました。
同様の課題を抱えている方の参考になれば幸いです。
最後に宣伝です。
Supershipではプロダクト開発やサービス開発に関わる人を絶賛募集しております。
ご興味がある方は以下リンクよりご確認ください。
Supership 採用サイト
是非ともよろしくお願いします。