はじめに
プラットフォーム開発本部マイクロサービスアーキテクトグループの認可チームに所属している清水(@nx_smhl)です。
今年、認可チームではサーバのCloud移行に伴い、オンプレミスのMySQLからTiDB CloudへのDB移行を実施しました。特に、私たちが管理している認可サーバはDMMの全サービスが依存する重要なコンポーネントであり、サービス停止を伴わない形での移行が求められました。
本記事では、このゼロダウンタイムでのDB移行を、ストラングラーフィグパターンとTiDBのデータベース比較ツール「sync-diff-inspector」によって実現した事例をご紹介します。
どのようにして実現したか、ご興味のある方は是非最後まで読んで頂けますと幸いです。
移行の要件
認可サーバのDB移行では以下の要件を満たす必要がありました。
ゼロダウンタイムで移行する
認可サーバはDMMの全サービスが依存する基盤的なコンポーネントであるため、数秒の停止も大きな影響を与える可能性があります。そのため、移行期間中も認可サーバは稼働し続ける必要がありました。移行期間中、2つのDBは結果整合性でいい
認可サーバはリクエストごとに認可情報を参照する特性上、強整合性ではなく結果整合性で許容できるケースが多くあります。移行期間中はオンプレMySQLとTiDB Cloud両方にデータを書き込みつつ、最終的にTiDB Cloud上のデータがMySQLと整合していればよいと判断しました。
これらの要件から、データを徐々に新環境へ切り替えていく形で移行する必要がありました。
DBの移行方法
データベースの移行方法は「ストラングラーフィグパターン (Strangler Fig Pattern)」を採用しました。以下は簡略化した工程になります。
工程1. 旧システムと新システムを並行稼働させる
既存のオンプレMySQLと新たなTiDB Cloudを並列で動かすことで、新旧2つのデータベースが同時に存在している状態にします。
工程2. 書き込みを新旧データベース双方に実行する
書き込み処理をオンプレMySQLだけでなく、TiDB Cloudにも実行するようにします。
工程3. 読み取り経路を徐々に切り替える
読み取りは段階的にTiDB Cloud側へスイッチし徐々にオンプレMySQLからの読み込みをなくしていきます。
工程4. データ整合性の検証・同期
新DB(TiDB Cloud)と旧DB(オンプレMySQL)のデータが一致していることを確認しながら、最終的に新DBをメインDBとして確定します。
これらの工程により、全ての機能を一度に切り替えることなく、サービスを止めずに移行を進めることが可能となります。
DB移行に生じる課題
ここで、上記の工程でDB移行を実施する際に課題があります。
移行開始時点で生じるデータ差分への対処
工程2で書き込みを始める際、バックアップ取得時点からリアルタイムで差分データが増え続けるためTiDB Cloudへのインポート後には旧DBと新DB間で差分が発生します。その結果、外部キー制約などでエラーが生じる可能性があります。コミットやロールバック失敗時の修正クエリの実装が大変
ストラングラーフィグパターンの書き込み処理において、分散トランザクションを実装する必要性があります。特にコミットやロールバックに失敗した場合、その不整合を解消するための修正クエリを独自に実装・適用する必要があり、運用コストが増大します。データ整合性の保証
最終的に新DBに切り替える前に、旧DBと新DB間でデータに差分がないことを検証する必要があります。
sync-diff-inspector
上記課題を解決するために導入したのが、TiDBを開発しているPingCAPが提供するデータ比較ツール「sync-diff-inspector」です。こちらのツールはOSSとして提供されています。 sync-diff-inspectorは、MySQL互換のDBのデータを比較・検証できるツールで、差分検出だけでなく、差分修正用のクエリを自動生成が可能です。
実行すると以下の画像のように、修正クエリをSQLファイルとして出力してくれます。
ゼロダウンタイムでDB移行する都合上、オンラインでDB間の差分を検証する必要があります。 しかし、sync-diff-inspectorは本来オフラインでの実行を想定したツールのため、実運用への適用には設定値や実行方法などの工夫が必要でした。
オンラインで実行するために工夫したこと
オンラインでsync-diff-inspectorを稼働している環境では、以下のようなエラーが度々発生しました。
[FATAL] [diff.go:548] ["the count is not correct"] [count1=37854] [count2=37977] [count=75832] ...
このエラーを調査した結果、sync-diff-inspectorがDB間でデータ差分を検知する際に用いる検証範囲の分割処理が原因でした。sync-diff-inspectorは、指定したインデックス範囲内の行数が1000よりも多い場合に、その範囲をさらに細分化し、より狭い範囲ごとに行数やチェックサムを検証しようとします。その際、分割前後で合計行数が合わないと上記のエラーが発生します。
この現象は、オンライン(稼働中)のデータベースに対してsync-diff-inspectorを実行している状況でよく起こります。DB上のテーブルはリアルタイムで更新されているため、範囲分割前後で行数を再取得した際にレコードの増減があるためです。
この問題の対策として、sync-diff-inspectorの設定ファイルにあるchunk-size
パラメータを調整することが有効です。chunk-sizeは、分割基準となるチャンクの目安行数を決めるためのパラメータであり、これを十分小さい値に設定することで、範囲分割をせず直接行比較するケースが増え、上記エラーの発生を回避できることがあります。デフォルトでは50000以上になるように実装されていますが、私たちの場合はchunk-sizeを1000にして運用していました。
- config.tomlの設定例
[table-configs.config1] chunk-size = 1000
このようにchunk-sizeを小さくすることで、差分検出の過程での行数不一致が発生しにくくなります。ただし、この設定はチャンク分割戦略を変えるため、比較処理の性能や速度に影響する場合があります。実運用では性能とエラー回避を両立させるため、適宜chunk-size値を調整してください。 また、chunk-sizeを小さくすると出力されるSQLファイルの数が多くなってしまう場合がありますので、修正クエリの実行方法についても考慮する必要が出てくるかもしれません。
sync-diff-inspectorによる課題解決
私たちは、sync-diff-inspectorを用いてTiDB Cloudの差分を自動的に修正するスクリプト(以下、sync-diff-inspectorスクリプト)を作成しました。これにより、差分を検知・修正でき、前述したDB移行の課題を解消できました。
移行開始時点で生じるデータ差分への対処
TiDB Cloudへバックアップのインポート後、書き込みを開始した段階で発生していた初期差分を、sync-diff-inspectorスクリプトによって修正しました。これにより、並行稼働中のDB間で生じる不整合を早期に取り除くことが可能となりました。
分散トランザクションにおける修正クエリの容易な適用
sync-diff-inspectorは差分検出に加え、修正クエリを自動生成します。この機能を活用することにより、アプケーション側にコミットやロールバックの失敗を検知する仕組みを実装すれば、sync-diff-inspectorスクリプトを実行することで簡易に差分を解消できるようになりました。その結果、実装コストと運用コストを大幅に削減できました。
データ整合性の保証
sync-diff-inspectorは本来、移行完了時に両DB間のデータ一致を保証するためのツールですが、定期的に実行することで移行期間中の差分も監視できます。これにより、最終的にTiDB Cloudへの切り替え時点でデータの整合性を確認し、安全なDB移行を実現できました。
おわりに
本記事では、認可サーバのオンプレMySQLからTiDB Cloudへのゼロダウンタイム移行を、ストラングラーフィグパターンとsync-diff-inspectorを用いて達成した事例をご紹介しました。今回得た知見や手法は、今後同様の移行プロジェクトやシステムリプレイスにおいて、参考指標となると期待しています。
sync-diff-inspectorはオフライン想定のツールですが、オンラインの環境でも十分に活用できました。もし、MySQL互換のDB移行を計画する際は是非一度sync-diff-inspectorを触ってみてください。
プラットフォーム開発本部では、一緒に働く仲間を募集しています。
ご興味のある方はこちらへ!
dmm-corp.com