Auroraレプリカラグ監視|AuroraReplicaLag
目次
Aurora PostgreSQL でリーダーインスタンスに参照クエリを流す構成は、ライターの負荷を下げる定番の手段です。一方で運用が始まると必ず出てくるのが「リーダーから読んだデータは、どのくらい古い可能性があるのか」「同期遅延をどう監視すればよいのか」という問いです。
AuroraReplicaLag というメトリクスがあることは分かっても、何ミリ秒までなら正常なのかを決める根拠が見つからず、アラートを設定できないまま運用に入ってしまうケースは少なくありません。さらに Aurora のレプリカは、一般的な PostgreSQL のストリーミングレプリケーションとは仕組みが違うため、PostgreSQL の知識をそのまま当てはめると判断を誤ります😇
この記事では、(1) 見るべきメトリクスと取得手順、(2) Aurora 特有のラグ発生メカニズム、(3) 自分の環境で閾値を決める手順、(4) ラグが急増したときの切り分け順、をまとめます。RDS / Aurora の運用トラブル全体の切り分けについては RDS・Aurora 運用・トラブル解決ガイド|仕組み・障害切り分け・性能監視の全体像 も合わせて参照してください。
🎯 結論:見るべきメトリクスと、閾値を決める順番
まずリーダーごとの AuroraReplicaLag を時系列で見る
Aurora のレプリカ遅延を見るときの中心は、CloudWatch の AWS/RDS ネームスペースにある次のメトリクスです。
| メトリクス | 単位 | 粒度 | 主な用途 |
|---|---|---|---|
AuroraReplicaLag |
ミリ秒 | インスタンス(DBInstanceIdentifier) |
個々のリーダーの遅延を特定する |
AuroraReplicaLagMaximum |
ミリ秒 | クラスター(DBClusterIdentifier) |
クラスター内で最も遅れているリーダーの値 |
AuroraReplicaLagMinimum |
ミリ秒 | クラスター(DBClusterIdentifier) |
クラスター内で最も遅れが小さいリーダーの値 |
出発点はリーダーインスタンス単位の AuroraReplicaLag を時系列で見ることです。クラスター単位の Maximum / Minimum はクラスター全体の傾向を掴むには便利ですが、どのインスタンスが遅れているかは分かりません。リーダーが複数ある構成では、特定の 1 台だけが遅れているのか、全台が一様に遅れているのかで、疑うべき原因がまったく変わります。
1 台だけ遅いなら、そのインスタンス固有の要因(インスタンスクラス、そのリーダーに集中しているクエリ負荷、そのインスタンスに対する運用操作)を疑います。全台が一様に遅いなら、ライター側の書き込み負荷を疑います。この分岐を最初に作れるかどうかで、その後の切り分けの速さが変わります。
閾値は「アプリが許容できる読み取りの鮮度」から逆算する
AuroraReplicaLag に「一律で何ミリ秒以内なら正常」という推奨値は存在しません。許容できる遅延がアプリケーション要件にしか依存しないため、汎用的な基準を作りようがないからです。
たとえば同じクラスターでも、次のように要件は大きく変わります。
- 更新直後の自分のデータをリーダーから読み返す画面 → 遅延にほぼ耐えられない(そもそもリーダーを使うべきでない可能性がある)
- 日次集計のダッシュボード → 数秒〜数十秒の遅延は業務影響なし
- 全文検索や一覧の 2 ページ目以降 → 中間的。ユーザー体験として許容できる鮮度をプロダクト側と決める必要がある
したがって閾値決定の手順は次の順番になります。
- アプリケーションごとに「許容できる読み取りの鮮度」を言語化する(例:この API はリーダーから読むが、更新から X 秒以内に反映されていればよい)
- 通常運用時とバッチ実行時のラグのベースラインを実測する
- ベースラインより十分に高く、かつ要件の許容値より低いところにアラート閾値を置く
要件の許容値をそのまま閾値にすると「鳴ったときにはもう業務影響が出ている」状態になります。逆にベースラインぎりぎりに置くと平常時のゆらぎで鳴り続け、アラートが無視されるようになります。この 2 つの数値に挟まれた範囲を取るのが実務上の落としどころです😓
いま鳴っているアラートへの初動
すでにアラートが鳴っていて困っている場合は、次の順で見ます。詳細は後半の切り分け手順で展開します。
- 対象クラスターの全リーダーの
AuroraReplicaLagを重ねて描画し、1 台だけか全台かを判別する - 同じ時間帯のライター側の書き込み系メトリクス(
WriteThroughput、WriteIOPS、DMLThroughput、CommitLatencyなど)を並べ、書き込み負荷のスパイクと一致しているか確認する - バッチ処理・大量 INSERT/UPDATE・インデックス再作成・データ移行などのジョブ実行時刻と突き合わせる
- RDS のイベント履歴と API 呼び出し履歴を見て、インスタンスの削除・名称変更・スケーリング等の運用操作が同時刻に行われていないか確認する
💡 多くのケースで、原因は 2 と 3 のどこかに現れます。
🔍 なぜラグが生まれるのか:Aurora の共有ストレージと redo 転送の仕組み
ライターとリーダーは同じクラスターボリュームを共有している
Aurora では、ライターインスタンスとリーダーインスタンスが同一のクラスターボリュームを共有しています。リーダーは自分専用のデータファイルのコピーを持ちません。
一般的な PostgreSQL のストリーミングレプリケーションでは、スタンバイは自分のデータディレクトリを持ち、プライマリから送られてきた WAL を再生して自分のストレージにデータを書き戻すことでレプリカを維持します。つまりデータの実体が 2 セット存在します。
Aurora はこの構造を採りません。ライターは変更を redo ログレコードとしてストレージ層に送り、ストレージ層(複数 AZ に分散したストレージノード群)がクォーラムベースでその redo を永続化し、ページの再構成を担います。リーダーは、そのストレージ層を同じボリュームとして読むだけです。
この設計から、いくつかの運用上の帰結が生まれます。
- リーダーを追加してもストレージの二重化コストは発生しない(データのコピーを作らない)
- リーダー側に「WAL の受信・再生の遅れ」という概念が、ストリーミングレプリケーションと同じ意味では存在しない
- リーダーを増やしてもライター側の WAL 送信負荷が線形に増える構造ではない
それでもラグがゼロにならない理由:バッファキャッシュの更新・無効化
ではなぜ AuroraReplicaLag がゼロにならないのか。鍵は各インスタンスがメモリ上に持つバッファキャッシュです。
リーダーインスタンスもクエリを高速に処理するため、読み取ったページを自分のバッファキャッシュ(shared_buffers 相当の領域)に保持します。ここでライター側があるページを更新したとすると、リーダーのキャッシュに残っている古いページは無効になります。これを放置すると、リーダーは古いページをメモリから返し続けてしまいます。
そこで Aurora では、ライターからリーダーへ、リーダーのバッファキャッシュ上のページを更新・無効化するためのログ(redo)が非同期で送られます。リーダーはこれを受け取り、自分のキャッシュに反映します。
AuroraReplicaLag が表しているのは、主にこの反映の遅れです。ストレージ上のデータが遅れているのではなく、リーダーのメモリ上の状態がライターの最新の変更にどれだけ追いついていないかを示す値だと捉えると、後の切り分けが素直になります。
この非同期転送があるため、遅延は原理的にゼロにはなりません。ただし通常は非常に小さい値に保たれます✨
書き込みが集中するとラグが増える流れ
ラグが増えるメカニズムは、ここまでの理解から素直に導けます。
- ライター側で大量の更新が発生する(バルク INSERT、広範囲の UPDATE/DELETE、VACUUM に伴うページ変更、インデックス構築など)
- ライターからリーダーへ送られる redo の量が増える
- リーダー側でのキャッシュ更新・無効化の処理が増え、反映が追いつかなくなる
AuroraReplicaLagが一時的に上昇する
つまり、ラグの上昇は基本的に「書き込み量の関数」です。読み取りクエリを増やしてもラグの主原因にはなりにくく、逆にライター側で長時間の重いバッチが走る構成では、その時間帯にラグのピークが出るのが自然です。
💡 運用上の判断基準としては、ラグが増えたときにまずライター側の書き込み量の変化を探す、という順序が最も高い確率で当たります。
🤔 よくある誤解:PostgreSQL のストリーミングレプリケーションのラグとは別物
WAL を受け取って再生する方式との違い
現場でよく聞かれる誤解が、「Aurora のレプリカラグは PostgreSQL のストリーミングレプリケーションのラグと同じもの」というものです。名前も似ていますし、どちらも「プライマリの変更がレプリカに届く遅れ」を表すので混同されやすいのですが、観測している対象が違います。
| コミュニティ版 PostgreSQL のストリーミングレプリケーション | Aurora PostgreSQL のリーダー | |
|---|---|---|
| データの実体 | プライマリとスタンバイでそれぞれ保持 | クラスターボリュームを共有し、レプリカはコピーを持たない |
| 転送されるもの | WAL レコード | リーダーのバッファキャッシュを更新・無効化する redo |
| レプリカ側の処理 | WAL 受信 → 再生(startup / WAL receiver プロセス)→ 自分のストレージへ反映 | 受け取った redo を自分のキャッシュに反映 |
| 主な遅延指標 | pg_stat_replication の write_lag / flush_lag / replay_lag、LSN 差分 |
CloudWatch の AuroraReplicaLag(ミリ秒) |
| 遅延が膨らむ典型要因 | WAL 生成量、ネットワーク帯域、スタンバイの I/O 性能、再生と読み取りクエリの競合 | ライター側の書き込み量 |
実務的に効いてくる差は次の点です。
- 監視の入口が違います。ストリーミングレプリケーションなら SQL(
pg_stat_replication)でプライマリ側から測れますが、Aurora のリーダー遅延は CloudWatch メトリクスで見るのが基本です - WAL の滞留によるディスク枯渇という故障モードが、同じ形では出ません。物理スタンバイやレプリケーションスロットを使う構成では、スロットが進まずに WAL が溜まってストレージを食い潰す事故が典型ですが、Aurora の読み取りレプリカはこのモデルではありません(一方で Aurora PostgreSQL で論理レプリケーションを使う場合はスロットと WAL 保持の問題が普通に発生します。その挙動は PostgreSQL論理レプリケーションのWAL保持とスロット運用 にまとめています)
- チューニングの打ち手が違います。ストリーミングレプリケーションならスタンバイ側の I/O やネットワーク、再生関連パラメータが検討対象になりますが、Aurora では「ライター側の書き込みをどう平準化するか」が中心の議論になります
⚠️ なお、リーダー側で長時間クエリが走っているときの挙動や関連パラメータの扱いは、Aurora のエンジンバージョンによって異なる部分があります。バージョン固有の挙動は必ず該当バージョンの公式ドキュメントで確認してください。
「一律で◯ミリ秒以内が正常」という基準が存在しない理由
ここまでの仕組みを踏まえると、汎用的な閾値が作れない理由もはっきりします。AuroraReplicaLag の値は、少なくとも次の要素の組み合わせで決まります。
- ライター側の書き込み量とその時間分布(常時一定か、夜間バッチで跳ねるのか)
- 更新されるページの局所性(狭い範囲の更新か、テーブル全体を書き換えるのか)
- リーダーのインスタンスクラスとキャッシュサイズ
- リーダー上で走っている読み取りクエリの性質
同じ Aurora PostgreSQL でも、ワークロードが違えば平常時のラグの水準は変わります。他社の事例やインターネット上の数値をそのまま閾値に転用すると、鳴らないアラートか鳴りすぎるアラートのどちらかになります。閾値は自分の環境で実測して決めるしかありません。実測の具体的な手順は後半で扱います。
🛠️ ラグが増えたときの切り分け手順
ステップ1:レプリカ個別の AuroraReplicaLag で対象を特定する
最初にやるのは、対象クラスターに属するすべてのリーダーインスタンスの AuroraReplicaLag を同じグラフに重ねることです。CloudWatch のメトリクス画面でも、後述する CLI でも構いません。
ここで見るのは 3 点です。遅れているのは 1 台か全台か(前述のとおり、疑う原因が分岐します)。上昇の形が急峻なスパイクか、なだらかな上昇か、階段状に高止まりしているか。そしてピーク後に平常値へ戻っているかどうかです。戻っているなら一時的な負荷、戻らないなら継続要因があります。
スパイクして戻る形は、バッチや一括更新のような有限の書き込みイベントに対応することが多いパターンです。高止まりしたまま戻らない場合は、書き込み負荷が恒常的に増えたか、そのインスタンス側に継続的な要因があると考えます。
ステップ2:AuroraReplicaLagMaximum / Minimum でクラスター全体の傾向を見る
次にクラスター単位の AuroraReplicaLagMaximum と AuroraReplicaLagMinimum を並べます。この 2 本を同時に見る価値は、両者の開き方に情報があることです。
Maximum と Minimum がほぼ重なって一緒に上がっているなら、クラスター全体に共通の要因があり、ライター側の書き込み負荷が第一候補になります。Maximum だけが跳ねて Minimum は平常という形なら、特定インスタンス固有の要因で、ステップ1で特定した「1 台だけ遅い」ケースと整合します。
💡 長期のキャパシティ計画や、リリース前後での傾向比較にも Maximum / Minimum は使いやすい指標です。日次・週次のダッシュボードにはクラスター単位、アラートにはインスタンス単位、という使い分けが実務では扱いやすい構成になります。
ステップ3:ライター側の書き込み負荷・バッチ処理と突き合わせる
ラグが急増した場合、ライター側の書き込み負荷が原因である可能性が高い、というのが仕組みからの帰結です。ここを丁寧に突き合わせます。
ライターインスタンスの次のメトリクスを並べて見ます。
WriteThroughputとWriteIOPSはストレージへの書き込み量そのものを表しますDMLThroughputは INSERT / UPDATE / DELETE の実行レートですCommitLatencyはコミット遅延で、書き込みが詰まり始めているサインになりますCPUUtilizationとDatabaseConnectionsで負荷の全体像を押さえます
データベース側からは、ラグ上昇と同じ時刻に何が動いていたかを確認します。
-- ライターで、長時間実行中のセッションを確認する
SELECT pid,
usename,
application_name,
state,
now() - xact_start AS xact_duration,
now() - query_start AS query_duration,
wait_event_type,
wait_event,
left(query, 120) AS query
FROM pg_stat_activity
WHERE state <> 'idle'
AND backend_type = 'client backend'
ORDER BY xact_start;
そして、ジョブスケジュール表とグラフを重ねます。夜間バッチ、日次の集計処理、データ連携、インデックス再作成、アーカイブ削除といった「まとまった書き込みを出す処理」の実行時刻とラグのピークが一致すれば、そこが原因です。
この突き合わせで一致が取れた場合、対処の方向性は次のようになります。
- 書き込みを平準化する(バッチのコミット単位を小さくして分散させる、一括 UPDATE を分割する)
- ラグに敏感な参照処理を、バッチ時間帯だけライターに向ける、あるいはその時間帯の実行を避ける
- そもそも「バッチ実行中はリーダーのラグが上がる」ことを仕様として受け入れ、アラート閾値をバッチ時間帯のベースラインを踏まえて設計する
3 番目は逃げのように見えますが、業務影響がないなら最も合理的な選択です。無害なピークで鳴るアラートを放置するより、明示的に設計に織り込むほうが運用は健全になります👍
ステップ4:インスタンスの削除・名称変更など運用操作の有無を確認する
見落としやすいのが、運用操作に伴う一時的なラグ急増です。リーダーインスタンスの削除や名称変更の際に、一時的にラグが跳ねることがあります。この種の挙動は特定操作に紐づく一時的なもので、性能問題ではありません。
⚠️ したがって、この値を閾値設計の根拠に使ってはいけません。「削除作業をしたらラグが 1 桁増えたので、閾値はそれより上に」という設計をすると、本来検知したい平常時の異常を取りこぼします。運用操作起因のスパイクは、閾値を上げるのではなく、作業時間帯のアラート抑止や作業記録との突き合わせで扱うのが筋です。
確認手順は 2 つです。
# RDS のイベント履歴(対象クラスター/インスタンスの操作・状態変化)
aws rds describe-events \
--source-identifier <クラスター識別子> \
--source-type db-cluster \
--duration 1440
aws rds describe-events \
--source-identifier <インスタンス識別子> \
--source-type db-instance \
--duration 1440
イベント履歴に該当する記録がなければ、CloudTrail で DeleteDBInstance、ModifyDBInstance、ModifyDBCluster などの API 呼び出し履歴を確認します。「誰も操作していないはず」という前提が崩れることは珍しくないので、必ず履歴で裏を取ります。イベント履歴と API 呼び出し履歴を使った切り分けの型は RDS Multi-AZ フェイルオーバー原因の確認手順 で詳しく扱っているので、同じ手順をラグ調査にも流用できます😱
📊 監視の実装:CLI での取得とアラート設計
aws cloudwatch get-metric-data での取得パラメータ
ベースラインを取る段階では、GUI でグラフを眺めるだけでなく、数値として取得して手元で集計できるようにしておくと分析が進みます。aws cloudwatch get-metric-data を使います。
指定すべきパラメータは次のとおりです。Namespace は AWS/RDS、MetricName は AuroraReplicaLag、Dimensions は DBInstanceIdentifier に対象リーダーインスタンスの識別子を指定します。Period はメトリクスの送信間隔に合わせます(送信間隔より短い Period を指定しても、データポイントは増えません)。Stat は用途に応じて Average と Maximum を使い分けます。
まず、どの次元でメトリクスが存在するかを確認します。
aws cloudwatch list-metrics \
--namespace AWS/RDS \
--metric-name AuroraReplicaLag
次に、特定のリーダーの値を取得します。
cat > query.json <<'EOF'
[
{
"Id": "lagAvg",
"MetricStat": {
"Metric": {
"Namespace": "AWS/RDS",
"MetricName": "AuroraReplicaLag",
"Dimensions": [
{ "Name": "DBInstanceIdentifier", "Value": "<レプリカインスタンス識別子>" }
]
},
"Period": 60,
"Stat": "Average"
},
"ReturnData": true
},
{
"Id": "lagMax",
"MetricStat": {
"Metric": {
"Namespace": "AWS/RDS",
"MetricName": "AuroraReplicaLag",
"Dimensions": [
{ "Name": "DBInstanceIdentifier", "Value": "<レプリカインスタンス識別子>" }
]
},
"Period": 60,
"Stat": "Maximum"
},
"ReturnData": true
}
]
EOF
aws cloudwatch get-metric-data \
--metric-data-queries file://query.json \
--start-time <開始時刻(ISO8601)> \
--end-time <終了時刻(ISO8601)> \
--output json
Period の 60 は、メトリクスの送信間隔に合わせて調整してください(モニタリング設定によって送信間隔は変わります)。
クラスター全体の傾向を取る場合は、MetricName を AuroraReplicaLagMaximum / AuroraReplicaLagMinimum に、Dimension を DBClusterIdentifier に変えます。
cat > cluster-query.json <<'EOF'
[
{
"Id": "lagClusterMax",
"MetricStat": {
"Metric": {
"Namespace": "AWS/RDS",
"MetricName": "AuroraReplicaLagMaximum",
"Dimensions": [
{ "Name": "DBClusterIdentifier", "Value": "<クラスター識別子>" }
]
},
"Period": 60,
"Stat": "Maximum"
},
"ReturnData": true
},
{
"Id": "lagClusterMin",
"MetricStat": {
"Metric": {
"Namespace": "AWS/RDS",
"MetricName": "AuroraReplicaLagMinimum",
"Dimensions": [
{ "Name": "DBClusterIdentifier", "Value": "<クラスター識別子>" }
]
},
"Period": 60,
"Stat": "Minimum"
},
"ReturnData": true
}
]
EOF
aws cloudwatch get-metric-data \
--metric-data-queries file://cluster-query.json \
--start-time <開始時刻(ISO8601)> \
--end-time <終了時刻(ISO8601)> \
--output json
💡 Average と Maximum を両方取るのは、平常時の水準を Average で、スパイクの有無を Maximum で判断するためです。Average だけを見ていると、短時間の大きなラグが平均に埋もれて見えなくなります。逆に Maximum だけを見るとスパイクに引っ張られてベースラインを過大評価します。
必要な IAM 権限
メトリクス取得に必要な権限は最小限で済みます。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"cloudwatch:GetMetricData",
"cloudwatch:ListMetrics"
],
"Resource": "*"
}
]
}
cloudwatch:GetMetricData が本体で、メトリクスの一覧取得に cloudwatch:ListMetrics を使います。これらの API はリソースレベルの権限指定に対応していないため、Resource は * を指定します。「* を避けたい」という要件がある場合は、IAM ポリシーの Condition や、そもそも実行ロールを監視用途に限定するといったアプローチで絞り込みを検討してください。
なお、aws rds describe-events を併用する場合は rds:DescribeEvents も必要になります。
検証環境で書き込み負荷をかけてベースラインを取る
ここが監視設計の核心です。本番と同等の構成の検証環境で、ライター側に意図的に書き込み負荷をかけ、そのときのリーダーの AuroraReplicaLag の推移を実測します🔥
やることは次の 4 ステップです。
- 検証用の Aurora PostgreSQL クラスター(ライター+リーダー)を、本番に近いインスタンスクラスで用意する
- ライター側に大量の書き込み処理を実行する。本番で走っているバッチと同じ処理を流せるのが理想。難しい場合は、対象テーブルへの大量 INSERT や広範囲の UPDATE で代替する
- その間、リーダーの
AuroraReplicaLagを前節の CLI で継続取得する - 取得した時系列を、負荷なし区間と負荷あり区間に分けて集計する
集計で出しておきたい値は、無負荷時の Average と Maximum、書き込み負荷時の Average と Maximum、そして負荷投入からラグが上昇し始めるまでの時間と負荷終了後に平常値へ戻るまでの時間です。
最後の立ち上がり・回復の時間は、閾値の評価期間(何分間連続で超えたらアラートにするか)を決めるのに直結します。ラグが上がってすぐ戻る性質のワークロードなら評価期間を長めにしてノイズを削り、上がったら戻らない性質なら短めにして早期検知を優先します。
検証環境が用意できない場合でも、本番の平常時とバッチ時間帯のデータを一定期間(少なくとも 1 週間以上、月次バッチがあるなら 1 か月以上)収集してからアラートを設定する、という順番は守るべきです。閾値を先に決めてから運用に入ると、ほぼ必ず調整のやり直しになります😇
ベースラインからアラート閾値に落とし込む
ベースラインが取れたら、次の 3 つの数値を並べます。
- 平常時のラグの上限(無負荷〜通常負荷時の Maximum の水準)
- 想定内の高負荷時のラグの上限(バッチ実行時の Maximum の水準)
- アプリケーションが許容できる読み取りの鮮度(要件から決めた値)
そのうえで、アラートは 2 段構成にすると運用しやすくなります。警告(Warning)は想定内の高負荷時の上限をやや超えた水準に置き、「想定外の何かが起きている」ことに気づくための通知だけにして即時対応は求めません。重大(Critical)はアプリケーション要件の許容値に達する手前の水準に置き、ここに到達したら業務影響が出る可能性があるのでオンコール対応の対象にします。
⚠️ このとき、1 と 3 の大小関係を必ず確認してください。平常時のラグがすでにアプリ要件の許容値に近いなら、閾値設計ではなくアーキテクチャのほうに問題があります。その参照処理をリーダーに向けている前提自体を見直す(ライターに戻す、キャッシュ層を挟む、要件を緩和する)議論に持ち込む必要があります。
また、前述のとおりインスタンスの削除や名称変更に伴う一時的なラグ急増を閾値の根拠にしてはいけません。計画作業の時間帯はアラートを抑止し、作業記録と突き合わせられるようにしておくのが正しい扱いです。
❓ よくある質問
AuroraReplicaLag は何ミリ秒までなら問題ない?
一律の推奨値はありません。許容値はアプリケーションが必要とする読み取りの鮮度にのみ依存します。同じ Aurora PostgreSQL でも、書き込み量・更新の局所性・インスタンスクラス・リーダー上のクエリ負荷が違えば平常時の水準は変わります。
やるべきことは、(1) 自分の環境で平常時と高負荷時のベースラインを実測する、(2) アプリ要件から許容値を決める、(3) その 2 つの間に閾値を置く、の 3 ステップです。他環境の数値の流用は避けてください。
レプリカごとにラグの値は違う?
違います。AuroraReplicaLag はリーダーインスタンス単位のメトリクスで、DBInstanceIdentifier 次元ごとに個別に取得できます。だからこそクラスター単位の AuroraReplicaLagMaximum / AuroraReplicaLagMinimum が別途用意されています。
インスタンスクラスが異なる、あるいは特定のリーダーに重い分析クエリが集中しているといった条件では、同じクラスター内でもラグの水準に差が出ます。アラートはインスタンス単位で設定するのが基本です。クラスター単位の Maximum だけで監視すると、どのインスタンスが問題なのか分からず、切り分けの初手で足踏みします。
ラグが大きいときライターに切り替えるべき?
「業務影響が出ているか」で判断します。一時的なスパイクで平常値に戻っているなら切り替えは不要で、原因(ライター側の書き込みイベント)を特定し、必要なら平準化を検討します。アプリ要件の許容値を超えたラグが継続しているなら、該当する参照処理をライターに向ける判断はあり得ます。
ただし、ライターへの切り替えは書き込み負荷が高いインスタンスに読み取り負荷を追加する行為です。ラグが大きい状況は、多くの場合ライター側が書き込みで忙しい状況でもあります。そこに参照クエリを寄せると、ライターのレスポンス悪化やコミット遅延を招き、状況が悪化することもあります。
現実的な設計は、「ラグに敏感な処理は最初からライターに向ける」「リーダーに向ける処理はラグを許容できるものに限定する」という振り分けを事前に決めておき、障害時の動的な切り替えに頼らないことです。アプリケーション側に接続先を切り替えるスイッチを持たせるにしても、切り替え後にライターが耐えられるかを事前に検証しておく必要があります。
Aurora MySQL でも同じ考え方でいい?
監視設計の考え方は共通で使えます。Aurora MySQL も共有クラスターボリューム方式であり、AuroraReplicaLag というメトリクスが提供されます。「リーダーごとに個別に取得する」「ベースラインを実測してから閾値を決める」「ラグ急増時はまずライター側の書き込み負荷を疑う」という手順はそのまま適用できます。
一方で、エンジン固有の要素はあります。Aurora MySQL では別クラスターへのバイナリログレプリケーションを組む構成もあり、その遅延は AuroraReplicaLag とは別のメトリクスで見ます。また読み取り一貫性に関するエンジン固有の機能やパラメータも存在します。提供されるメトリクスの一覧や関連パラメータはエンジンとバージョンで異なるため、使用するエンジン・バージョンのドキュメントを確認してください。
📝 まとめ:再発防止と運用チェックリスト
Aurora のレプリカラグ監視で押さえるべき点を整理します。
仕組みの理解
- Aurora のライターとリーダーは同一のクラスターボリュームを共有し、レプリカはデータのコピーを持たない
- それでもラグが発生するのは、リーダーのバッファキャッシュを更新・無効化する redo がライターから非同期に送られるため。
AuroraReplicaLagは主にこの反映の遅れを表す - したがってラグの主要因はライター側の書き込み量であり、PostgreSQL のストリーミングレプリケーション(WAL を受け取って自分のストレージに再生する方式)とは特性が異なる
監視設計のチェックリスト
- リーダーインスタンスごとに
AuroraReplicaLagを継続取得している - クラスター単位の
AuroraReplicaLagMaximum/AuroraReplicaLagMinimumもダッシュボードに置いている - 平常時とバッチ実行時のベースラインを実測済み(Average と Maximum の両方)
- アプリケーションごとに許容できる読み取りの鮮度を言語化してある
- 閾値がベースラインと許容値の間に置かれている(どちらかに張り付いていない)
- 評価期間(連続何分で発報するか)を、ラグの立ち上がり・回復の実測時間から決めている
- 計画的な運用操作(インスタンス削除・名称変更等)の時間帯はアラートを抑止する運用がある
- 運用操作時の一時的なスパイクを閾値の根拠に使っていない
- ラグに敏感な参照処理と、ラグを許容できる参照処理の振り分けが文書化されている
アラート発報時の切り分け順
- リーダー個別の
AuroraReplicaLagを重ねて、1 台か全台かを判別 - クラスター単位の Maximum / Minimum の開き方で裏取り
- ライターの書き込み系メトリクスとバッチ実行時刻を突き合わせ
- RDS イベント履歴と API 呼び出し履歴で運用操作の有無を確認
ラグ監視は「閾値をいくつにするか」から考え始めると行き詰まります。仕組みを理解し、実測し、アプリ要件から逆算するという順番を守れば、自分の環境に合った根拠のある閾値にたどり着けます🎉
⚠️ なお、CloudWatch メトリクスの仕様、送信間隔、Aurora の内部挙動、CLI のパラメータは変更されることがあります。実際に設計・実装する際は、使用しているエンジンとバージョンに対応する AWS の公式ドキュメントで最新の内容を確認してください。