サービス更新プログラムのバージョン管理によるダウンタイムの排除

これまで、管理者はオンプレミス ソフトウェアを更新およびアップグレードするためにサーバーをオフラインにする必要がありました。 ただし、ダウンタイムはグローバルな 24 時間 365 日のサービスにとってまったく問題のない問題です。 最新のクラウド サービスの多くは、ユーザーがビジネスを運営する上で重要な依存関係となっています。 システムを停止するのに最適な時期はありません。重要なセキュリティと機能の更新プログラムをインストールしながら、チームはどのようにして継続的なサービスを提供できるでしょうか?

バージョン管理された更新プログラムを使用すると、これらの重要なサービスを顧客がアクティブに使用している間に、現行のバージョンから別のバージョンにシームレスに移行できます。 すべてのアップデートが難しいわけではありません。 フロントエンドのレイアウトやスタイルの更新は簡単です。 機能の変更は難しい場合がありますが、移行のリスクを軽減するためのよく知られた方法があります。 ただし、データ層から生じる変更により、特別な考慮が必要な新たな種類の課題が生じます。

レイヤーを個別に更新する

複数のデータセンターと個別のデータ ストレージに分散されたオンライン サービスでは、すべてを同時に変更できるわけではありません。 一般的なサービスがアプリケーション コードとデータベースに分割されており、これらはおそらく互いに独立してバージョン管理されている場合、それらの側の 1 つでバージョン管理の処理の複雑さを吸収する必要があります。

多くの場合、バージョン管理はアプリケーション コードで処理する方が簡単です。 大規模なシステムには通常、データベース内に存在する SQL など、かなりの量のレガシー コードが含まれています。 この SQL をさらに複雑にするのではなく、アプリケーション コードで複雑さを処理する必要があります。 具体的には、SQL のバージョン管理を理解する一連のファクトリ クラスを作成できます。

すべてのスプリント中に、そのバージョンで新しいインターフェイスを作成し、各データベース バージョンに一致するコードが常に存在するようにします。 デプロイ中にバイナリを簡単にロールバックできます。 新しいバイナリをデプロイした後に問題が発生した場合は、前のコードに戻してください。 バイナリのデプロイメントが成功した場合は、データベースのサービスを開始します。

では、これは実際にどのように機能するのでしょうか? たとえば、チームが現在 Sprint 123 をデプロイしているとします。 バイナリは Sprint 123 データベース スキーマを理解し、Sprint 122 スキーマも理解します。 一般的なパターンは、SQL スキーマのバージョン/スプリント N と N-1 の両方で動作することです。 バイナリはデータベースにクエリを実行し、通信しているスキーマのバージョンを特定して、適切なバインディングをロードします。 その後、アプリケーション コードは、新しいデータ スキーマがまだ利用できない場合に対処します。 新しいバージョンが利用可能になると、アプリケーション コードは、最新のデータベース バージョンで有効になる新しい機能の利用を開始できるようになります。

データ層のみでロールフォワードする

データベースがアップグレードされると、問題が発生した場合、サービスはロールフォワード状態になります。 オンライン データベースの移行は複雑で、多くの場合、複数のステップが必要となるため、通常はロールフォワードが問題に対処する最良の方法です。 つまり、アップグレードが失敗すると、ロールバックも失敗する可能性が高くなります。 チームが使用することを想定していないロールバック コードを構築してテストする労力に投資する価値はほとんどありません。

導入シーケンス

一連の列をデータベースに追加し、一部のデータを変換する必要があるシナリオを考えてみましょう。 この遷移はユーザーには見えないようにする必要があります。つまり、テーブル ロックをできる限り回避し、認識されないようにロックをできるだけ短い時間保持することを意味します。

最初に行うことは、データの同期を保つために SQL トリガーを使用して、場合によっては並列テーブルでデータを操作することです。 大規模なデータの移行と変換では、場合によっては、複数のスプリントにわたる複数のデプロイメントにまたがる複数のステップを実行する必要があります。

追加のデータまたは新しいスキーマが並行して作成されると、チームはアプリケーション コードのデプロイメント モードに入ります。 デプロイメント モードでは、コードがデータベースを呼び出すと、まずスキーマのロックを取得し、ストアド プロシージャの実行後にロックを解放します。 データベースへの呼び出しが発行されてからストアド プロシージャが実行されるまでの間、データベースは変更できません。

アップグレード コードはスキーマ ライターとして機能し、スキーマに対するライター ロックを要求します。 アプリケーション コードはリーダー ロックの取得を優先し、アップグレード コードはバックグラウンドでライター ロックの取得を試みます。 ライター ロックでは、テーブル上で少数の非常に高速な操作のみが許可されます。 その後、ロックが解放され、アプリケーションはデータベースの新しいバージョンが使用中であることを記録し、新しいデータベース バージョンと一致するインターフェイスを使用します。

データベースのアップグレードはすべて、移行パターンを使用して実行されます。 一連のコードとスクリプトはデータベースのバージョンを確認し、増分変更を加えてスキーマを古いバージョンから新しいバージョンに移行します。 すべての移行は自動化され、リリース管理サービスを通じて展開されます。

Web UI も、ユーザーを混乱させることなく更新する必要があります。 JavaScript ファイル、スタイル シート、またはイメージをアップグレードする場合は、クライアントによって読み込まれる古いバージョンと新しいバージョンが混在しないようにしてください。 これにより、ユーザーが編集中のフィールドなど、進行中の作業が失われる可能性のあるエラーが発生する可能性があります。 したがって、展開に関連付けられたすべてのファイルを、バージョン管理された別のフォルダーに配置して、すべての JavaScript、CSS、およびイメージ ファイルのバージョンを管理する必要があります。 Web UI がアプリケーション層にコールバックを行うと、指定されたバージョンのアセットがロードされます。 ユーザーのアクションによってページ全体が更新された場合にのみ、新しい Web UI がブラウザーに読み込まれます。 アップグレードによってユーザー エクスペリエンスが中断されることはありません。

次のステップ

Microsoft は、数十年にわたって世界最大のソフトウェア開発会社の 1 つです。 Microsoft が DevOps を使用して信頼性の高いシステムを運用する方法を学びましょう