Amazon RDS の マネージド PITR に関する注意点

SCSKの畑です。

初投稿以来ほぼ Web アプリケーション開発およびサーバレスアーキテクチャの話しかしてこなかったのですが、別の案件で最近にしては珍しくデータベース関連のサービス(Amazon RDS/Amazon ElastiCache)を扱っていたりするので、ボチボチそちらの話題についても書いていこうと思います。まあ Elasticache は KVS (Key-Value Store)でデータベース関連のサービスとまとめてしまうべきではないと思いつつも、文章的にそうした方が楽なので見逃してください。

ちなみに同案件における RDS は Aurora MySQL 及び RDS for MySQL あたりが中心です。ということで最初は小ネタから。

 

本題

RDS にはマネージドな PITR (Point-In-Time Recovery)機能があります。マネジメントコンソール上では「特定時点への復旧」メニューが該当します。

同案件では MySQL のレプリケーションを使用しているのですが、特定の障害パターンにおけるMySQL のレプリケーションの復旧手順において同機能を使用する予定で、マネジメントコンソールから使い方や機能を検証していました。その際、トータルでの復旧時間を短縮するために「(PITR 可能な)最新の時刻まで PITR する」手順にしようと考えていました。ただ、同機能における RPO は 以下 URL の通り最大 5 分となっています。

Amazon RDS の DB インスタンスを特定の時点に復元する - Amazon Relational Database Service
Amazon RDS DB インスタンスを特定の時点に復元します。

RDS は、DB インスタンスのトランザクションログを 5 分ごとに Amazon S3 にアップロードします。

Amazon RDS を使った災害復旧戦略の実装 | Amazon Web Services
Amazon RDS (Relational Database Service) は、リレーショナルデータベー

ご使用の DB インスタンスで自動バックアップが有効化されていると、Amazon RDS は 1 日の全データをスナップショットとして自動的に保存します。このスナップショットは、設定されたバックアップウィンドウの間に実行されます。同時にこの処理は、Amazon S3 へのトランザクションログを、(DB インスタンスが更新される) 5 分間に一度キャプチャーします。

基本的に RDBMS における PITR は、特定断面のバックアップをリストアした後に、データベースに対する更新内容と時刻情報がセットで記録されているトランザクションログ(REDOログ、バイナリログなど呼び方は製品によって異なります)をロールフォワードリカバリすることで実現します。つまり上記注釈の文言に従って言い換えると、トランザクションログがどの時点まで S3 にキャプチャーされているのかによって、どの時点まで DB をリカバリできるのかが変わってくるということになります。そして取得間隔は5分間であるため、RPO も最大5分となります。

上記のような仕組みであるが故に、どの時刻まで PITR できるのかをどうやって確認するのかなと当初考えていたのですが、以下のように「復元可能な最新時刻」という項目があり時刻情報も表示されているため、この項目を選択して RDS を復旧すれば(PITR 可能な)最新の時刻まで PITR することが可能と考えました。

念のため、対象の RDS に対して 0.1 – 0.2 秒ごとにレコードを INERT している状態で、先述の通り「復元可能な最新時刻」を選択した上で PITR の動作を検証してみたところ、以下のように想定通りの時点までデータがリカバリされていることを確認しました。なお、仕様上手順検証時の状況を再現できないので、今回のエントリ用に再現試験したものを載せている点ご了承ください。

PITR の期待動作は「指定した時刻」の直前の更新までがリカバリされていることです。上記例のように 2026-02-08 14:34:21 を指定して PITR した場合は、2026-02-08 14:34:20.999… までの更新がリカバリされ、DB 上に反映されていることが期待されます。

なお、製品やサービスによっては異なる挙動をする可能性も0とは言えないですが、私が今まで触ってきた RDBMS では全て同じ挙動をしていましたので基本的には共通認識のはず・・です。

mysql> select * from record_table order by id;
+------+---------------------+
| id   | updated_at          |
+------+---------------------+
| 9309 | 2026-02-08 14:34:20 |
| 9308 | 2026-02-08 14:34:20 |
| 9307 | 2026-02-08 14:34:20 |
| 9306 | 2026-02-08 14:34:20 |
| 9305 | 2026-02-08 14:34:20 |
| 9304 | 2026-02-08 14:34:20 |
| 9303 | 2026-02-08 14:34:20 |
| 9302 | 2026-02-08 14:34:19 |
| 9301 | 2026-02-08 14:34:19 |
| 9300 | 2026-02-08 14:34:19 |

(中略)

9310 rows in set (0.03 sec)

そこで改めて MySQL のレプリケーション復旧も含めた一連の復旧手順をテストしてみたところ・・なんと復旧した MySQL のレプリケーションにてデータの不整合が発生し、エラーで停止してしまいました。具体的には、レプリケーションにて本来伝播されるべき更新が PITR にてリカバリしたデータに既に含まれており、データの不整合(重複)が発生してしまったのが原因でした。一連の手順におけるオペミスはなかったことから、先般 PITR によりリカバリしたデータに問題があるのではないかと考えました。

込み入った話になるので今回の障害パターンにおける一連の復旧手順については深堀しませんが、ものすごく簡単に説明すると「MySQL のデータをマネージド PITR で特定時刻の断面にリカバリした後、その時刻以降のトランザクションログを対象としてレプリケーションすることで復旧する」という手順でした。

このため、PITR が先述したような期待動作をしないと、レプリケーションによる更新データの欠損ないしは重複が発生し、データの不整合が発生してしまいます。今回発生した事象は後者(更新データの重複)ですね。

そこで、改めてリカバリ直後のデータ断面を見たところ・・なんと、以下のように 2026-02-08 14:34:21 の更新データが含まれており、想定より先の時点までデータがリカバリされてしまっていることが発覚しました。2026-02-08 14:34:21 の更新データが4件含まれている分、合計のレコード数も1回目のリカバリデータと比較して増えています。

なお「復元可能な最新時刻」の仕様上同じ条件でのリトライができないため、以下データ例は1回目のリカバリ操作において異なる結果となったデータを想定して記載しています。(厳密には今回の再現試験では2回目が実際の試験結果で、1回目は想定の試験結果となりましたが、そのあたりの詳細は後ほど)
mysql> select * from record_table order by id;
+------+---------------------+
| id   | updated_at          |
+------+---------------------+
| 9313 | 2026-02-08 05:34:21 |
| 9312 | 2026-02-08 05:34:21 |
| 9311 | 2026-02-08 05:34:21 |
| 9310 | 2026-02-08 05:34:21 |
| 9309 | 2026-02-08 05:34:20 |
| 9308 | 2026-02-08 05:34:20 |
| 9307 | 2026-02-08 05:34:20 |
| 9306 | 2026-02-08 05:34:20 |
| 9305 | 2026-02-08 05:34:20 |
| 9304 | 2026-02-08 05:34:20 |
| 9303 | 2026-02-08 05:34:20 |

(中略)

9314 rows in set (0.03 sec)

1回目は想定通りの結果であったのにも関わらず2回目でこのような結果になったのが当初理解できずに混乱したのですが、、AWSのドキュメントを改めてもう一度見てみると、「復元可能な最新時刻」を選択した場合は以下の通りできるだけ最新の時点に復元するという記載となっていました。

Latest restorable time」 を選択してできるだけ最新の時点に復元するか、「カスタム」 を選択して時刻を選択します。

あ、これはひょっとしてそういうことか?と思い当たり、以下のように「特定時刻を明示的に指定してPITRを実行」を選択してリトライしたところ・・

想定通りの時点(=1回目の試験結果の通り)にデータが PITR されました!念のため何回か試しましたが、全て期待通りの結果になっていました。つまりそれぞれ以下のような動作となるため、(厳密な)PITR を使用したい場合は「特定時刻を明示的に指定してPITRを実行」を選択する必要がある、というのが結論となります。

  • 「復元可能な最新時刻」は、表示されている時刻を指定した PITR ではなくS3 にキャプチャーされているトランザクションログを全て使用して復元可能な最新時点までリカバリを実行
  • 「特定時刻を明示的に指定してPITRを実行」は、表記の通り PITR を実行
    • その時刻指定において「復元可能な最新時刻」に表示されている時刻を参考にすることは可能

先の検証において1回目と2回目の結果に差異があったのも頷けるところで、1回目は本来 PITR により期待したデータ断面にたまたまリカバリできただけということですね。先述の通り今回のエントリ用の再現試験では2回目の結果となったのもその裏返しと言えます。

RDBMS においてこのように「戻せるところまで戻す」というロールフォワードリカバリ操作はもちろん可能です。一例として ORACLE では SQL だと「alter database recover database until cancel」文、RMAN だと「recover database」コマンドがそれぞれ対応しています。そしてこのコマンド例を見ると分かる通り「戻せるところまで戻す」という操作には本質的に時刻情報は含まれないはずなんですよね。戻せるところまで戻した結果として「何月何日何時何分の時点に復旧された」ということが分かるので。

それが故にマネジメントコンソールの画面が分かりづらかったところはあります。横に最新時刻が表示されているということは、その時刻に PITR するオペレーションを項目として独立しているのかな?と早とちりしてしまったというか。「復元可能な最新時刻」に表示されている時刻はあくまで目安というか、S3 にキャプチャ済みのトランザクションログの最新時刻なのでしょうかね?

AWS のドキュメントの記述は、上記のようなトランザクションログを使用した DB のリカバリ操作の挙動を理解している人であればそう解釈できなくもないですが、本来の PITR ではないということは明記しておいた方が良いように思いました。

 

まとめ

繰り返しになりますが、正直「復元可能な最新時刻」という表記が分かりづらいというか誤解を招くと思うので、表記だけでも直した方がいいと思いました。私のように画面だけ見ると絶対勘違いする人いるんじゃないかと思います。。まあ今回のように一回テストすれば大体分かることではありますが。

論理障害からの復旧にこういう機能を使う分にはデータの中身を見て判断することになると思うのでそこまで気にならない挙動かもしれません。が、今回のようなMySQLレプリケーションの復旧など、データの断面を厳密に特定する必要がある用途での使用は NG ですので気を付けましょう。

本記事がどなたかの役に立てば幸いです。

タイトルとURLをコピーしました