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 分となっています。
RDS は、DB インスタンスのトランザクションログを 5 分ごとに Amazon S3 にアップロードします。

ご使用の DB インスタンスで自動バックアップが有効化されていると、Amazon RDS は 1 日の全データをスナップショットとして自動的に保存します。このスナップショットは、設定されたバックアップウィンドウの間に実行されます。同時にこの処理は、Amazon S3 へのトランザクションログを、(DB インスタンスが更新される) 5 分間に一度キャプチャーします。
上記のような仕組みであるが故に、どの時刻まで PITR できるのかをどうやって確認するのかなと当初考えていたのですが、以下のように「復元可能な最新時刻」という項目があり時刻情報も表示されているため、この項目を選択して RDS を復旧すれば(PITR 可能な)最新の時刻まで PITR することが可能と考えました。
念のため、対象の RDS に対して 0.1 – 0.2 秒ごとにレコードを INERT している状態で、先述の通り「復元可能な最新時刻」を選択した上で PITR の動作を検証してみたところ、以下のように想定通りの時点までデータがリカバリされていることを確認しました。なお、仕様上手順検証時の状況を再現できないので、今回のエントリ用に再現試験したものを載せている点ご了承ください。
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 によりリカバリしたデータに問題があるのではないかと考えました。
そこで、改めてリカバリ直後のデータ断面を見たところ・・なんと、以下のように 2026-02-08 14:34:21 の更新データが含まれており、想定より先の時点までデータがリカバリされてしまっていることが発覚しました。2026-02-08 14:34:21 の更新データが4件含まれている分、合計のレコード数も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回目の結果となったのもその裏返しと言えます。
まとめ
繰り返しになりますが、正直「復元可能な最新時刻」という表記が分かりづらいというか誤解を招くと思うので、表記だけでも直した方がいいと思いました。私のように画面だけ見ると絶対勘違いする人いるんじゃないかと思います。。まあ今回のように一回テストすれば大体分かることではありますが。
論理障害からの復旧にこういう機能を使う分にはデータの中身を見て判断することになると思うのでそこまで気にならない挙動かもしれません。が、今回のようなMySQLレプリケーションの復旧など、データの断面を厳密に特定する必要がある用途での使用は NG ですので気を付けましょう。
本記事がどなたかの役に立てば幸いです。



込み入った話になるので今回の障害パターンにおける一連の復旧手順については深堀しませんが、ものすごく簡単に説明すると「MySQL のデータをマネージド PITR で特定時刻の断面にリカバリした後、その時刻以降のトランザクションログを対象としてレプリケーションすることで復旧する」という手順でした。
このため、PITR が先述したような期待動作をしないと、レプリケーションによる更新データの欠損ないしは重複が発生し、データの不整合が発生してしまいます。今回発生した事象は後者(更新データの重複)ですね。