DMSを使ったDB移行でTimestamp列の時刻ズレに苦戦した話
メディア統括本部 サービスリライアビリティグループ(SRG)の小原です。
#SRG(Service Reliability Group)は、主に弊社メディアサービスのインフラ周りを横断的にサポートしており、既存サービスの改善や新規立ち上げ、OSS貢献などを行っているグループです。
本記事は、DMSによるDB移行時に起きたTimestamp型の時刻ズレ問題とその対応について説明します。
時刻ズレ - 発端
とあるオンプレMySQLをDMSを使用してAWS Auroraに移行する際に、Timestamp型を含むテーブルの時刻がずれていることが発覚しました。
構成は以下のようになっていて、オンプレ側にDMS要件を満たすための新しいレプリカサーバを作成し、DMSのソースサーバとしています。
サーバは全てRow-based Replication、TimezoneはAsia/Tokyo(UTC+9)で統一してあります。

時刻ズレの内容としては、ソースサーバ上のレコードに登録されている時刻から9時間プラスされたデータがAurora側にレプリケートされているという状態でした
サーバ | 時刻データ |
on-prem Source | 10:00:00 |
on-prem New Replica | 10:00:00 |
Aurora | 19:00:00 |
実はこの現象について心当たりがあり、DMSの を設定していたことが影響しているのではないかと考えていました。この設定は、ソースサーバのTimestamp型の値がUTCであるのに対してDMS上でtimezoneの差分を計算してターゲットに適用するというもの。
こちらもあまり意識せずにAsia/Tokyoで統一していました。
serverTimeZone 設定はずす
もともと としていた設定を外してみます。
ざっと見た感じだと時刻ズレがなくなっているように見えました。
しかし、問題はまだ続きます。
時刻ズレ - フルロード編
DMSの設定を変更したので、一度フルロードからやり直します。
同期完了後、ふと気づきます。
また時刻ズレてる!!!!!
今度はソースサーバと比較して9時間マイナスされたデータがAurora側で発見されました。
状況を調べると、どうやらフルロード対象のレコードがズレているようでした。また、同期中に更新されたレプリケーションデータはズレていませんでした。
サーバ | フルロードされた時刻データ(ズレあり) | レプリケーションされた時刻データ(ズレなし) |
on-prem Source | 10:00:00 | 10:05:00 |
on-prem New Replica | 10:00:00 | 10:05:00 |
Aurora | 01:00:00 | 10:05:00 |
serverTimeZoneの値を変更して解決するような問題ではないようです。
serverTimeZone設定有無とDMSの挙動について
これまでの結果からserverTimeZoneの設定有無とDMSの挙動をまとめます
serverTimeZone有 | serverTimeZone無 | |
フルロード | ズレなし | ズレあり |
レプリケーション | ズレあり | ズレなし |
フルロード時とCDCレプリケーション時で時刻ズレが発生する挙動がserverTimezoneの有無で逆転しています。
つまり、DMSのタスクとしてフルロード+継続的なレプリケーションを行う場合、必ずどちらかの同期処理時にTimestamp型の時刻ズレが起きてしまうことがわかります。
おそらくフルロード時はSQL Read、レプリケーション時はBinlog ReadによるROWベースの実際の更新値を参照するためこのような違いが生じると想像しています。
SQL Read時はセッションTimezoneがDMSの設定依存であり、デフォルトでUTCなのでserverTimeZoneが設定されていれば差分計算すると値が正しくなります。
レプリケーション時はレプリカサーバ上のBinlogに記録されているTimezone込みの値を参照し、デフォルトでUTC+9のデータが参照・反映されますが、serverTimeZoneの設定があるとさらに9時間プラスされていた、という考えになります。
この状況を解決するためにいくつか方法を考えました。
- Auroraのtimezoneサーバ変数をUTCに変更する(現在UTC+9)
- タスクをフルロード(serverTimeZone有)、継続レプリケーション(serverTimeZone無)でそれぞれ分割
- Timestamp → Datetimeに型変更
それぞれ考慮、検証しDatetimeに変換する方法を採用しました。
メリット | デメリット | |
Auroraのtimezone変数をUTCに変更 | 既存DBへの影響は皆無 | 最終的にUTC+9に戻したいが、戻せるタイミングが移行切り替え時のみで限定的(サービス稼働中に切り替えする想定なので実施困難) |
タスクを分割 | 既存DBへの影響は皆無 | レプリケーションタスクがテーブルごとに定義が必要そうで現実的ではない |
Datetimeに変換 | 日時リテラルのDMS同期はフルロード,レプリケーション問わず時刻ズレは発生しない Timestampの2038年問題を解決できる | Alter実行の時間が読めない |
採用した理由として、Datetime型であればレプリケーションによるズレは発生しないこと、DMSソースであるオンプレのレプリカサーバのみをDatetime変換することで稼働しているサービスに影響をなくすことが可能だったことが挙げられます。
また、Datetimeへの変換にかかるAlterの実行時間は読めないもののDBのデータの規模感がそれほど大きくないので何日もかからないと予想しました。
懸念点として、そもそもTimestamp型は内部的にUTCで格納され、取得時にセッションのTimezoneに変換して表示する仕様です。Datetimeに変換する際に値がどうなるか確認が必要でした。
検証の結果、Alter実行時のセッションのTimezoneがUTC+9であれば、既存のレコードは正しくUTC+9 to UTC+9 でDatetimeに変換でき、変換中にソースサーバからレプリケーションされる時刻データもUTC+9のまま反映されることわかりました。
最終的な構成
Datetime型に変換することで無事に不整合なくフルロード+レプリケーションすることができました。

終わりに
レプリケーション不整合の内容を第三者に説明するのってややこしいですね。。。
DMSを使ったDB移行時にはTimestamp型を含むテーブルがないかご確認ください。
他にも簡単に解決できる方法があれば教えてください
SRG では一緒に働く仲間を募集しています。
ご興味ありましたらぜひこちらからご連絡ください。