データベースの移行: コンセプトと原則(パート 2)

Last reviewed 2024-03-11 UTC

このドキュメントでは、障害シナリオを含むデータベース移行プロセスの設定と実行について説明します。このドキュメントは 2 部構成の後半です。パート 1 では、オンプレミスまたは他のクラウド環境から Google Cloud にデータベースを移行する必要があるクラウド アーキテクトを対象に、ダウンタイムがほぼゼロのデータベース移行のコンセプト、原則、用語について説明しています。

データベース移行の設定

このセクションでは、データベース移行のフェーズについて説明します。まず、移行の設定を行います。移行が完了し、クライアントをターゲット データベースに切り替えたら、ソース データベースを削除します。必要であれば、移行による問題が切り替え後に発生した場合に備えてフォールバック プランを実装します。フォールバックはビジネスの継続性の確保に役立ちます。

移行中は、導入されるスキーマやデータの変更に特に注意する必要があります。これらの変更による影響については、このドキュメントの後半にある移行時の動的な変更をご覧ください。

ターゲット スキーマの仕様

ターゲット データベース システムごとにスキーマを定義し、作成する必要があります。同種のデータベースを移行する場合は、ソース データベースのスキーマをターゲット データベースにエクスポートして、ターゲット データベースのスキーマを作成することで、仕様をより短い時間で作成できます。

スキーマ名の付け方は重要です。たとえば、ソースとターゲットで同じスキーマ名を使用することが考えられます。これによりクライアントの切り替えは簡単になりますが、データを比較する場合など、ツールがソース データベース スキーマとターゲット データベース スキーマに同時に接続すると、ユーザー側で混乱の生じることがあります。構成ファイルでスキーマ名を抽象化し、ターゲット データベース スキーマにソースと異なる名前を付けると、スキーマを区別しやすくなります。

異種のデータベースに移行する場合は、ターゲット データベースごとにスキーマを作成する必要があります。このエンジニアリング プロセスでは、同じ操作を何回か繰り返すことが必要になる場合があります。たとえば、移行を実施する前に、移行プロセスやデータの変更に合わせてスキーマをさらに変更することが必要になる場合があります。

移行をテストして実行するときは、多くの場合、ターゲット データベースを複数回作成するため、スキーマの作成プロセスも繰り返すことが必要になります(インストール スクリプトで行うのが理想的です)。コード管理システムを使用すると、スクリプトのバージョンを管理して整合性を維持できます。また、スクリプトの変更履歴にアクセスすることもできます。

クエリの移行と実行のセマンティクス

最終的には、クライアントをソース データベース システムからターゲット データベース システムに切り替える必要があります。同種のデータベースを統合する場合、スキーマが変更されなければ、クエリも変更されません。クライアントはターゲット データベース システムでテストする必要がありますが、クエリに合わせてクライアントを変更する必要はありません。

一般に、異種のデータベースを移行する場合は、ソース データベースとターゲット データベースのスキーマが異なるため、クエリの変更が必要になります。ソース データベースとターゲット データベースでデータ型が一致していないこともあります。ソース データベース システムで使用できるクエリ言語のすべての機能が、ターゲット データベース システムで使用できるとは限りません。また、その逆もあり得ます。極端な場合、ソース データベース システムのクエリをターゲット システムの複数のクエリに変換しなければならないこともあります。クエリ言語でできる処理がソース データベースよりもターゲット データベースのほうが多い場合は、ソース データベースの複数のクエリをターゲット データベースで 1 つにまとめることもあります。

クエリのセマンティクスが異なる場合もあります。たとえば、一部のデータベース システムでは、トランザクション内で発生した更新をトランザクション内ですぐに具体化されます。この場合、同じデータアイテムが読み取られると、更新された値が取得されます。また、直ちに更新を行わず、トランザクションが commit されるまで待機するシステムも存在します。ソース データベース システム上のロジックが、具体化される書き込みに依存している場合、ターゲット データベース上の同じロジックによって、誤ったデータやエラーが発生する可能性があります。

クエリを移行する場合は、すべての機能をテストし、移行の前後でクライアントの動作が変わらないようにする必要があります。データレベルでのテストも可能ですが、これはクライアント レベルでのテストに代わるものではありません。クライアントはビジネス ロジックの観点からクエリを実行するので、クライアントでのテストはビジネス ロジック レベルで行う必要があります。

移行プロセス

異種のデータベースを移行する場合、ソース データベース システムから抽出されたデータを変更してターゲット データベースに挿入する方法を移行プロセスで指定します。 このドキュメントのデータの変更で説明するように、データアイテムをソース データベースから抽出してターゲット データベースに転送する前に、データの変更を定義して実行します。

同種のデータベースを移行する場合は、ソース データベースとターゲット データベースのスキーマが同等であれば、データの変更は不要です。データは、ソース データベースから抽出された状態でターゲット データベースに挿入されます。

データベース移行システムによっては、いくつかの構成が必要になる場合があります。たとえば、変更および転送するデータをデータベース移行システムに断続的に保存するかどうかを指定する必要があります。データを保存すると移行プロセス全体が遅くなる可能性がありますが、障害発生時に復旧にかかる時間は大幅に短縮されます。検証タイプの指定が必要になることもあります。たとえば、一部のデータベース移行システムでは、ソースシステムとターゲット システムにクエリを送信し、クエリの実行時点までに移行されたデータセットが同等になるようにします。また、エラー処理で障害復旧時の動作を指定する必要があります。この要件は、使用しているデータベース移行システムによって異なります。

当然のことですが、データの移行は繰り返しテストする必要があります。確認済みのデータアイテムがすべて移行され、データ変更によるエラーがなく、十分なパフォーマンスとスループットが得られることを移行のテストで検証することが理想的です。これにより、時間内での移行が可能になります。

フォールバック プロセス

データベースの移行中、計画的なダウンタイムが発生しない限り、ソース データベースは稼働を続けます。データベースの移行に失敗すると、最悪の場合、移行を中止してターゲット データベースを初期状態にリセットする必要があります。エラーを解決したら、データベースの移行を再開できます。この障害と解決作業が稼働中のソース データベース システムに影響することはありません。

データベースの移行が完了して、クライアントをターゲット データベースに切り替えた後に障害が発生すると、クライアントが障害と解決作業の影響を受け、正常に稼働できなくなることもあります。障害が迅速に解決され、クライアントのダウンタイムが短時間で済むこともありますが、最悪の場合、障害が解決されないか、解決に時間がかかるため、クライアントをソース データベースに戻さなければならないこともあります。

クライアントをソース データベースに戻す場合、ターゲット データベースのすべてのデータ変更をソース データベースに戻す必要があります。このプロセスは、完全な別のデータベース移行として設定し、実行できます。ただし、この時点でクライアントはターゲット データベース上で動作しなくなっているため、大幅なダウンタイムが発生します。

この状況でクライアントのダウンタイムを回避するには、元のデータベースの移行が完了した直後に移行プロセスを開始する必要があります。ターゲット データベース システムに適用されたすべての変更は、ソース データベース システムに直ちに反映されます。このアプローチに従うと、ターゲット データベース システムとソース データベース システムの両方が常に同期されます。

ターゲット データベースからソース データベースへのフォールバックを準備するには相当な手間がかかります。そこで、フォールバック プロセスを導入してテストすべきかどうかを検討し、導入しない場合はその結果(重大なダウンタイム)について理解しておくことが重要です。

データベース移行の実行

データベースの移行には 5 つのフェーズがあります。このセクションでは、それぞれのフェーズについて詳しく説明します。6 つ目のフェーズとしてフォールバックがありますが、これは通常のデータベース移行の範囲外で、例外となります。

このセクションで説明するプロセスは、ダウンタイムがほぼゼロの異種データベース間で移行する場合のものです。大幅なダウンタイムが発生する可能性がある場合は、バックアップ / 復元またはエクスポート / インポートのアプローチを使用して、最初の 3 つのフェーズ(初期読み込み、移行の継続、ドレイン)を 1 つにまとめます。

同種のデータベース間での移行は特殊なケースです。このタイプの移行では、ソース データベース システムが稼働している状態で、データを移行するデータベース管理システムのレプリケーション機能を使用できます(この機能をシステムでサポートしている場合)。

ここでは、データベース移行プロセスの要件に応じて変更が必要になるアプローチについて説明します。

フェーズ 1: 初期読み込み

移行フェーズは、すべてのソース データベースから移行対象に指定されたすべてのデータを移行することから始まります。データ移行の開始時は、ソース データベースが特定の状態で、移行中にその状態が変化していきます。

変更と移行が同時に発生する場合は、最初のデータアイテムが抽出される直前のデータベース システムの時間を記録しておきます。このタイムスタンプを使用することで、それ以降に発生したデータベースの変更をトランザクション ログから取得することが可能になります。初期読み込みでは、すべてのデータを一貫した状態で読み取る必要があります。整合性のないデータセットの読み取りを防ぐため、データベースを短時間ロックする場合もあります。

このフェーズは次のプロセスから構成されます。

  • データベースの移行を開始する直前にデータベースのシステム時間を記録する。
  • 初期読み込みを行い、移行が必要なソース データベースからデータセット(完全または一部)をクエリで取得する。リレーショナル データベース モデルでは、SELECT * などのクエリ、選択付きのクエリ、プロジェクションなどが初期読み込みで実行されます。移行プロセスでは、プロセスの指定に従ってデータを変更します。

通常、クライアントは初期読み込みの実行中にソース データベースに変更を行います。開始前にデータベース システムの時間を記録しているので、このような変更を後でトランザクション ログから取得できます。

初期読み込みフェーズが完了すると、ソース データベース システムからターゲット データベース システムへの初期データセットの移行が完了します。ただし、移行中にクライアントがソース データベースを変更する可能性があるため、ソース データベースとターゲット データベースの同期はまだ行いません。これらの変更はフェーズ 2 でキャプチャして移行します。

フェーズ 2: 移行の継続

移行の継続中に次の 2 つのことを行います。まず、初期読み込みの開始後にソース データベースで発生した変更を読み取ります。その後、これらの変更をキャプチャしてターゲット データベースに転送します。

このフェーズは次のプロセスから構成されます。

  • フェーズ 1 で記録したデータベース システムの時間から移行プロセスを再開する。その時点からのトランザクション ログを読み取り、すべての変更をターゲット データベース システムに適用します。
  • データを変更する。移行プロセスでは、指定に基づいてこのステップが行われます。

記録したデータベース システムの時間の後にログに記録された変更が初期読み込みのフェーズで転送されていることがあります。その場合、こうした変更が移行の継続中に再度適用される可能性があるため、変更が 2 回適用されないように移行プロセスを定義する必要があります。たとえば、識別子を使用します。変更されたデータアイテムが初期読み込みで転送され、その挿入がトランザクション ログに記録されたとします。データアイテムに識別子を適用することで、移行システムはデータアイテムがすでに存在し、挿入の必要がないことを認識できます。

移行フェーズが進んでいくと、ターゲット データベースがソース データベースと完全に同期された状態か、ほぼ同期された状態になります。ソース データベース システムでの変更が移行されていないデータベースは、ほぼ同期された状態になります。

データベース移行システムの構成方法によっては、この相違がわずかな場合もあれば、大きな場合もあります。たとえば、効率性を高めるには、すべての変更をすぐに移行する必要はありません。また、ソースに対する変更が急増すると、ソースに多大な負荷がかかることになります。通常、収集された変更は一括オペレーションでバッチとして移行されます。バッチが小さいと、ソースとターゲットの間で差異が少なくなりますが、変更が頻繁に行われた場合、ソースの負荷が大きくなる可能性があります。

バッチサイズが動的に構成されている場合は、移行フェーズの初期に大きなバッチを同期し、移行の進行状況に合わせてバッチのサイズを段階的に小さくしていくのが最適です。このアプローチにより、処理を効率的に行い、ソース データベースとターゲット データベースの差異を少なくすることができます。

フェーズ 3: ドレイン

クライアントをソース データベースからターゲット データベースに切り替える準備を行う前に、ソース データベースとターゲット データベースが完全に同期されている必要があります。ドレインは、残りの変更をソース データベースからターゲット データベースに移行するプロセスです。

このフェーズは次のプロセスから構成されます。

  • ソース データベース システムを静止状態にする。これは、ソース データベースでデータの変更が発生せず、トランザクション ログに追加の変更エントリが記録されない状態を意味します。
  • すべての変更がターゲット データベースへの移行を待機している状態にする。このプロセスでは、実際に変更のドレインを行います。
  • ドレインが完了したら、今後の増分バックアップの開始点を定義するため、ターゲット データベースをバックアップします。

ドレイン フェーズでソース データベース システムとターゲット データベース システムが同期され、これ以上データの変更は発生しません。

ドレインを確実に完了させるため、最後に挿入されたデータアイテムをソース データベースに書き込むこともできます。この最終挿入のデータアイテムが対応するターゲット データベースに転送されると、ドレイン フェーズが完了します。

フェーズ 4: 切り替え

ドレイン フェーズが完了したら、クライアントをソース データベースからターゲット データベースに切り替えることができます。次のベスト プラクティスをおすすめします。

  • 本番環境のデータベースに対するアクセスを有効にする前に、クライアントが正常に動作し、意図したとおりに動作することを確認します。テストケースの数によって、本番環境のデータベースの実際のダウンタイムが変わります。
  • クライアント アクセスを有効にする前に、ターゲット データベースをバックアップします。これにより、ターゲット データベースの初期状態を確実に復元できます。

切り替えが完了すると、クライアントは完全に動作し、本番環境のデータベース(この時点までのターゲット データベース)にアクセスを開始します。

フェーズ 5: ソース データベースの削除

本番環境のデータベースへの切り替えが完了したら、ソース データベースを削除できます。ソース データベースの最終バックアップを作成して、アクセス可能な最終状態を明確にしておくことをおすすめします。データ規制で、コンプライアンス上の理由から最終バックアップの保管が義務付けられている場合もあります。

フェーズ 6: フォールバック

フォールバックの実装は、移行時に発生する問題に対する安全策となります(きわめて重要なデータベース クライアントの場合は、フォールバックの実装は欠かせません)。フォールバックは移行と似ていますが、プロセスは逆になります。つまり、フォールバックではターゲット データベースからソース データベースへの移行を設定します。異種データベースの移行では、フォールバックの処理が複雑になります。そのため、データベース移行プロセスとターゲット データベースに接続されたアプリケーションがサービスレベル契約(SLA)を満たしていることを徹底的にテストした後にのみ、スイッチオーバーを行うことをおすすめします。

ソース データベースをドレインしてすべてのデータベースをバックアップしたら、ターゲット データベースの変更を識別し、切り替えを行う前に、これらの変更をソース データベースに反映させます。

この移行プロセスを構築すると、クライアントがターゲット データベースに変更を行った後に、ソース データベースと同期し、データを最新の状態にすることができます。フォールバックは、切り替えの数日後または数週間後に必要になることがあります。たとえば、クライアントが初めて機能にアクセスしたときに、すぐに修正できない機能の不具合でアクセスがブロックされることがあります。この場合、ソース データベースにアクセスするようにクライアントを切り替えることができます。クライアントを元に戻す前に、ターゲット データベースで行われたすべての変更をソース データベースにドレインする必要があります。

このアプローチでは、いくつかの点に注意する必要があります。

  • 逆方向の移行(ターゲット データベースからソース データベース)が可能になるように、ターゲット スキーマを設計する必要があります。たとえば、最初の移行プロセス(ソースからターゲット)に結合や集計がある場合、逆方向の移行は簡単ではありません。このような場合は、個々のデータがターゲット データベースでも使用可能な状態になっている必要があります。
  • ソース データベースにトランザクション ログがあっても、ターゲット データベースではそのような機能が使用できない場合があります。その場合は、逆方向の移行(ターゲットからソース)では差分クエリを使用する必要があります。この設定は、ターゲット データベースのスキーマに設計し、準備する必要があります。
  • フォールバックで有効にできるように、ソース データベースで稼働していたクライアントを使用可能な状態にしておく必要があります。機能の同等性を維持するため、ターゲット データベースにアクセスするクライアントに行った機能上の変更は、ソース データベースにアクセスするクライアントにも行う必要があります。

フォールバックは最終手段ですが、フォールバックの実装は不可欠であり、テストを含む完全なデータベース移行として扱う必要があります。

移行時の動的な変更

一般に、スキーマとデータ値は変更される可能性があるため、データベースは動的なシステムです。データベース スキーマはビジネス要件などの要因によって変わる可能性があり、データ値はスキーマの変更とともに、または独立して変化します。データ値の変更は、アプリケーションの実装に対応する変更とともに、いつでも動的に発生する可能性があります。以下では、データベースの移行で考えられる変更とその影響について説明します。

スキーマの変更

データベースは、事前に定義されたスキーマを必要とするシステムと、スキーマに依存しないシステムまたはスキーマレスのシステムに分類できます。一般に、事前に定義されたスキーマを必要とするシステムはスキーマの変更に対応しています(たとえば、リレーショナル システムでの属性や列の追加など)。

このようなシステムでは、チェンジ マネジメント プロセスで変更を制御する必要があります。チェンジ マネジメント プロセスを使用することで、制御された方法で変更を行うことができます。全体に一貫した変更を行うため、スキーマに依存するオペレーション(クエリやデータ移行プロセスなど)は同時に変更されます。

事前定義のスキーマを必要としないデータベース システムはいつでも変更できます。スキーマの変更は、承認されたユーザーだけでなく、プログラムによって行うことが可能な場合もあります。その場合、スキーマの変更はいつでも発生する可能性があります。スキーマに依存するオペレーション(クエリやデータ移行プロセスなど)が失敗する可能性があります。これらのデータベース システムで未承認のスキーマ変更を防ぐには、チェンジ マネジメント プロセスをシステムとして導入するのではなく、遵守すべき承認ルールとして導入する必要があります。

データの変更

一般に、スキーマによってデータ属性に使用可能なデータ値が制御されます。スキーマレス システムの場合、データ値に対する制約はありません。

いずれの場合も、これまで保存されていなかったデータ値が発生する可能性があります。たとえば、列挙型は多くのデータベース システムで一連の文字列として実装されています。プログラミング言語レベルでは、これらを列挙型としてクライアントに実装できますが、これは必ずしも必須ではありません。あるクライアントで有効な列挙型とみなされる値が別のクライアントではそのように扱われない可能性もあります。また、データ移行プロセスでは、列挙型の値よりも機能が重要になることもあります。新しい値が発生した場合、データ移行プロセスが失敗する可能性があります。

別の例として、JSON 構造のストレージを見てみましょう。多くの場合、JSON 構造は文字列型に格納されますが、アクセス時には JSON 値として解釈されます。JSON 構造が変更されても、データベース システムはその変更を検出しません。このため、文字列を JSON 値として解釈するデータ移行プロセスは失敗する可能性があります。

移行プロセスの変更

データベースの移行中にチェンジ マネジメントを行うのは容易ではなく、複雑な作業になります。結果としてデータの移行に失敗する可能性があります。また、データに不整合が生じる可能性もあります。必要な変更は、ソースとターゲットのデータベース システムを同期するドレイン フェーズが完了するまで遅らせるのが最適です。この時点での変更は、ターゲット データベースとそのクライアントに限定されます(ただし、フォールバックが実装されている場合は除きます)。

データの移行中に移行プロセスの変更が必要になった場合は、複雑な変更は行わず、最小限の変更にとどめることをおすすめします。また、ソースとターゲットのデータベースのテスト インスタンスを使用して、これらの変更をテストすることもできます。テストソースに本番環境のデータを読み込んでテスト対象に移行するのが理想的です。このアプローチを使用すると、進行中の本番環境への移行に影響を与えることなく、変更を確認できます。変更をテストして検証したら、本番環境のシステムに変更を適用します。

進行中のデータ移行プロセスで変更を行う場合は、データ移行システムを停止して再起動する必要があります。また、変更後のデータ移行プロセスの実施が必要になる場合もあります。その場合、初期データの読み込みフェーズから始める必要はありません。データ移行システムがテスト移行の実施に対応している場合は、その機能を使用することもできます。

データの移行中は、スキーマ、データ値、データ移行プロセスを変更しないことをおすすめします。変更を行った場合、明確な開始状態を定義するため、データ移行を最初からやり直さなければならないこともあります。いずれにしても、本番環境のデータでテストを行い、変更を適用する前にデータベースのバックアップを作成することが最も重要です。これにより、必要に応じてシステム全体をリセットし、整合性の取れた状態に戻すことができます。

移行の失敗を回避するための対策

データベースの移行中に予期しない問題が発生することがあります。このような問題に対して事前に対策を行っておく必要があります。計画が必要な領域は次のとおりです。

  • スループットが十分でない。負荷テストを行っていても、移行テストで十分なスループットが得られないことがあります。この問題の原因としては、ソース データベースの変更やネットワーク スロットリングが想定を上回る速さで増加しているなど、さまざまな要因が考えられます。こうした状況に対応するには、関連するすべてのコンポーネントを動的にスケールアップまたはスケールアウトできるように追加のリソースを準備しておきます。
  • データベースが不安定。ソースまたはターゲットのデータベースが不安定になり、データ移行プロセスが遅くなることがあります。また、断続的にアクセスできなくなることもあります。データ移行プロセスの復旧が頻繁に必要になることもあります。この場合、HA または DR に意図的に切り替えることで問題が解決することがあります。切り替えにより、機能していない環境(マシンとストレージ)が切り替わり、問題が軽減される可能性があります。この場合、切り替えとデータベース移行の復旧プロセスをテストし、切り替えによってターゲット データベースのデータに不整合が生じないようにする必要があります。
  • トランザクション ログファイルのサイズ超過。上限のあるファイルにトランザクション ログが保存されることがあります。この上限に達し、データベースの移行に失敗する可能性があります。リソースの制限に達したときに、データベース システムのどの部分を動的に再構成できるのか把握しておく必要があります。動的に構成できない要素がある場合は、初期サイズを慎重に決める必要があります。

事前のテストを現実的で完全なものにするほど、潜在的な問題を事前に解決できる可能性が高くなります。

次のステップ