web-dev-qa-db-ja.com

FlywayやLiquidBaseなどの進化型データベースツールの場合、ツールを統合するか、CIプロセスのスタンドアロンステップとして残した方がよいですか。

私の質問は言語やDBに依存しないと思いますが、このケーススタディでは、質問を理解するのに役立つ可能性があるため、具体的なテクノロジを提供します(英語では申し訳ありません)。

これは、severalTomcatによってホストされるJava-Springアプリケーションで、移行スクリプトによってスキーマがバージョン管理される1つの中央postgresql DBを備えています。バージョン管理には、FlywayDBやLiquidBaseなどのツールを使用します。

データベース移行ツールはいくつかの方法で使用できます。

  1. (Spring)アプリケーションに完全に統合:アプリケーションの起動時に、DB移行ツールはバージョン管理テーブルとローカルスクリプトディレクトリをチェックします。新しいスクリプトが見つかった場合、ツールによってスクリプトが実行され、データベースが更新されます。また、ハッシュの等価性などもチェックします。
  2. データベース移行ツールは、継続的インテグレーションプロセスの特定のステップで呼び出されます。 DBが更新され、アプリケーションがデプロイおよび開始されます。

最良の方法は何ですか?なぜですか?

私はいくつかの引数について考えました:

  • オプション1 pro:スキーマとコードが100%一致します。
  • オプション1のプロ:FlywayDBのドキュメントによると最高

ソース: https://flywaydb.org/documentation/api/

Flywayは、アプリケーションに統合されたときに最大のメリットをもたらします。 Flywayを統合することにより、手動による介入を必要とせずに、アプリケーションとそのデータベースが常に互換性を持つことを保証できます。 Flywayはデータベースのバージョンをチェックし、残りのアプリケーションが開始する前に新しい移行を自動的に適用します。最初にデータベースを移行して、残りのコードを処理できる状態にする必要があるため、これは重要です。

  • オプション1 con:何かが発生した場合、アプリケーションは最新バージョンに更新されていますが、データベースは更新されていません。このサーバーは使用できません。アプリケーションデプロイメントのロールバックシステムが構築されていない限り、db移行ツールのエラーをキャッチする機能があります。それは存在しますか、それとも自分で実装する必要がありますか?
  • オプション2プロ:db移行の問題を簡単にキャッチし、展開をロールバックしてキャンセルします。本番サーバーは以前と同じように稼働し続け、タイムアウトすることはありません。
  • オプション2のcon:デプロイが1つのサーバーで失敗した場合、古いコードは新しいDBスキーマと一致しませんが、アプリケーションは引き続き実行されます=>データが破損する可能性があります。

アプリケーションランタイムからのスクリプトを適用せずにDBスキーマ/コードバージョンの一致をチェックし続け、継続的インテグレーションプロセスからのDB移行スクリプトを適用することができたでしょうか。

この問題についてあなたの経験を共有してくれてありがとう。

編集:チェックしたところ、これらのツールはデータベースのロックを使用して、スキーマを更新しようとする複数のインスタンスを管理していました。

3
Poutrathor

この質問は、アプリケーションインスタンスの数が多く、共有DBが1つある状況で、dbとアプリケーションのアップグレードの失敗をどのように処理するか、そして最初に実行する必要がある問題に要約されます。

ダウンタイムをできる限り小さくすることが重要な場合は、展開を次の手順に分割してみます。

  1. データの損失を防ぐために、アプリケーションを短時間「読み取り専用」モードに設定します(このような機能を実装する必要がある場合があります)。

  2. DB(スキーマとデータ)を中間バージョンにアップグレードします。DBへの変更は、「下位互換性」のある列とテーブルの追加のようにのみ適用されます。そのため、古いアプリケーションバージョンは、少なくとも読み取り専用モードで動作します。元の列が現在削除されていない限り、データの移行を伴う「列を2つに分割する」などの操作でも、ここで可能です。この手順が失敗した場合は、DBをロールバックしてください。

  3. 次に、アプリケーションをアップグレードします。正常に更新されたアプリケーションは、再度読み取り/書き込みモードに切り替えることができます。 1つのアプリケーションサーバーのアップグレードが失敗した場合は、問題を修正します(またはサーバーをオフラインにします)。実行中のすべてのアプリケーションがアップグレードされるまで続行しないでください。

  4. DBを最終バージョンにアップグレードし、新しいアプリケーションバージョンでは不要になったテーブルや列の削除など、下位互換性のない変更をデータベースに適用します。

そうすれば、アプリケーションのロールバックシステムが不要になり、サイレントデータ破損のリスクがなくなります。

3
Doc Brown

私が言及しなかった移行をアプリケーションに含めない1つの本当に大きな理由があります:flywayはアプリケーションに与えてはならない高レベルの許可を必要とします。これは 重要なセキュリティ慣行 に違反しています。

起動時にアプリケーションでDBを更新することには、メリットがありません。これの2つの主なコンテキストを考えてみましょう。自動デプロイメントがあるか、何らかの手動デプロイメントがあります。前者では、flyway更新ルーチンを、アプリケーションの起動前のデプロイメントプロセスの一部にするだけです。 2番目のケースでは、手動プロセスは、アプリケーションの間違ったバージョンをデプロイするなどの問題が発生する可能性が高いことを意味し、スキーマの移行がそれにバンドルされていると、はるかに大きな問題が発生する可能性があります。

データベーススキーマの変更は、(ほとんどの場合)アプリケーションの配置よりもはるかに影響が大きく、リスクが高く、修正が困難です。アプリケーションの展開を正しく設定した場合、間違ったバージョンのアプリケーションを展開すると、修正するのは簡単です。正しいバージョンを展開します。これは、ソリューションにコンテナーを使用する場合に特に当てはまります。通常、データベーススキーマの変更はそれほど単純ではありません。多くの場合、データの変換が伴うため、常に元に戻せるとは限りません。変更のリスクが高いほど、変更について慎重に行う必要があります。スキーマの変更は、通常はリスクが少ないものの副作用として発生するため、問題が発生します。

1つのサーバーで展開が失敗した場合、古いコードは新しいDBスキーマと一致しませんが、アプリケーションは引き続き実行されます=>データの破損が発生する可能性があります。

アプリケーションが起動時にスキーマをチェックし、それがアプリケーションが期待するバージョンと一致することを確認することをお勧めします。スキーマがアプリケーションのバージョンと一致していない場合、アプリケーションの起動に失敗するはずです。

スキーマの移行を分離しておくと、展開プロセスをより自由に管理できます。ローリングデプロイを使用するクラスタ化アプリがある場合、主要なスキーマ変更を行うためにすべてを停止する必要がある場合があります。そのスキーマの変更がローリングデプロイメントの一部である場合、つまり、古いバージョンが一部のノードでまだ稼働中である場合にどうなるかを検討してください。アプリケーションにスキーマをアップグレードさせると状況が単純化するように見えるかもしれませんが、特にデータベースを「修正」しようとするアプリケーションの誤ったバージョンを誤って開始した場合は特に、事態が複雑になります。

3
JimmyJames