次の方法で共有


モノリシックな永続化のアンチパターン

アプリケーションのすべてのデータを 1 つのデータ ストアに配置すると、リソースの競合につながるか、データ ストアが一部のデータに適していないため、パフォーマンスが低下する可能性があります。

コンテキストと問題

これまで、アプリケーションは、アプリケーションが格納する必要があるデータの種類に関係なく、1 つのデータ ストアを使用しました。 組織では、この方法を使用して、アプリケーションの設計を簡略化したり、開発チームの既存のスキル セットと一致させたりしました。

最新のクラウドベースのシステムには、多くの場合、追加の機能要件と非機能要件があります。 これらのシステムでは、ドキュメント、イメージ、キャッシュされたデータ、キューに登録されたメッセージ、アプリケーション ログ、テレメトリなど、さまざまな種類のデータを格納する必要があります。 従来のアプローチに従い、この情報をすべて同じデータ ストアに配置すると、2 つの主な理由からパフォーマンスが低下する可能性があります。

  • 同じデータ ストアに大量の関連のないデータを格納して取得すると、競合が発生し、応答時間が遅くなり、接続エラーが発生する可能性があります。
  • どのデータ ストアが選択されているかに関係なく、すべての種類のデータに最適とは限りません。 または、アプリケーションが実行する操作用に最適化されていない可能性があります。

次の例は、データベースに新しいレコードを追加し、結果をログに記録する ASP.NET Web API コントローラーを示しています。 ログは、ビジネス データと同じデータベースに格納されます。

public class MonoController : ApiController
{
    private static readonly string ProductionDb = ...;

    public async Task<IHttpActionResult> PostAsync([FromBody]string value)
    {
        await DataAccess.InsertPurchaseOrderHeaderAsync(ProductionDb);
        await DataAccess.LogAsync(ProductionDb, LogTableName);
        return Ok();
    }
}

ログ レコードが生成される速度は、ビジネス操作のパフォーマンスに影響を与える可能性があります。 また、アプリケーション プロセス モニターなどの別のコンポーネントがログ データを定期的に読み取って処理する場合は、ビジネス操作にも影響を与える可能性があります。

解決策

使用に応じてデータを分離します。 データ セットごとに、そのデータ セットの使用方法に最も適したデータ ストアを選択します。 前の例では、アプリケーションはビジネス データを保持するデータベースとは別のストアにログを記録する必要があります。

public class PolyController : ApiController
{
    private static readonly string ProductionDb = ...;
    private static readonly string LogDb = ...;

    public async Task<IHttpActionResult> PostAsync([FromBody]string value)
    {
        await DataAccess.InsertPurchaseOrderHeaderAsync(ProductionDb);
        // Log to a different data store.
        await DataAccess.LogAsync(LogDb, LogTableName);
        return Ok();
    }
}

問題と考慮事項

  • 使用方法とアクセス方法に基づいてデータを分離します。 たとえば、ログ情報とビジネス データを同じデータ ストアに格納しないでください。 これらの種類のデータには、さまざまな要件とアクセス パターンがあります。 ログ レコードは本質的にシーケンシャルですが、ビジネス データはランダム アクセスを必要とする可能性が高く、多くの場合リレーショナルです。

  • データの種類ごとにデータ アクセス パターンを検討します。 たとえば、書式設定されたレポートやドキュメントを Azure Cosmos DB などのドキュメント データベースに格納します。 Azure Cache for Redis を使用して一時データをキャッシュします。

  • このガイダンスに従ってもデータベースの制限に達している場合は、データベースをスケールアップします。 また、水平方向にスケーリングし、データベース サーバー間で負荷をパーティション分割することも検討してください。 ただし、パーティション分割には、アプリケーションの再設計が必要になる場合があります。 詳細については、「 データのパーティション分割」を参照してください。

問題を検出する

システムがデータベース接続などのリソースを使い果たしたときに、システムの速度が大幅に低下し、最終的に障害が発生する可能性があります。

原因を特定しやすくするために、次の手順を実行できます。

  1. システムをインストルメント化して、主要なパフォーマンス統計を記録します。 各操作のタイミング情報をキャプチャします。 また、アプリケーションがデータの読み取りと書き込みを行うポイントをキャプチャします。

  2. 運用環境で数日間システムを監視し、システムの使用方法を実際に把握します。 このプロセスを実行できない場合は、一般的な一連の操作を実行する仮想ユーザーの現実的な量でスクリプト化されたロード テストを実行します。

  3. テレメトリ データを使用して、パフォーマンスが低下している期間を特定します。

  4. これらの期間中にアクセスされたデータ ストアを特定します。

  5. 競合が発生する可能性があるデータ ストレージ リソースを特定します。

診断例

次のセクションでは、前述のサンプル アプリケーションにこれらの手順を適用します。

システムのインストルメント化と監視

次のグラフは、前に説明したサンプル アプリケーションのロード テストの結果を示しています。 このテストでは、最大 1,000 人の同時ユーザーのステップ ロードが使用されます。

SQL ベースのコントローラーのロード テストのパフォーマンス結果を示すグラフ。

負荷が 700 人のユーザーに増加すると、スループットも増加します。 しかし、その時点でスループットが安定し、システムは最大容量で実行されるように見えます。 平均応答は、ユーザーの負荷に応じて徐々に増加し、システムが需要に対応できないことを示しています。

パフォーマンスが低い期間を特定する

運用システムを監視すると、パターンに気付く場合があります。 たとえば、応答時間が毎日同時に大幅に低下する場合があります。 通常のワークロードまたはスケジュールされたバッチ ジョブによって、この変動が発生する可能性があります。 あるいは、特定の時間帯にシステムにより多くのユーザーがいるかもしれません。 これらのイベントのテレメトリ データに焦点を当てる必要があります。

応答時間の増加と、共有リソースに対するデータベース アクティビティまたは入出力 (I/O) の増加との相関関係を探します。 相関関係がある場合は、データベースがボトルネックになっている可能性があることを意味します。

これらの期間中にアクセスされるデータ ストアを特定する

次のグラフは、ロード テスト中のデータベース スループット ユニット (DTU) の使用率を示しています。 DTU は、使用可能な容量の測定値です。 CPU 使用率、メモリ割り当て、I/O レートの組み合わせです。 DTU の使用率はすぐに 100%に達します。 前のグラフでは、この時点でスループットがピークに設定されました。 データベースの使用率は、テストが完了するまで高いままです。 最後にかけてわずかに低下することがあります。これは、スロットリング、データベース接続の競合、またはその他の要因による可能性があります。

データベースのリソース使用率を示す Azure クラシック ポータルのデータベース モニターを示すグラフ。

データ ストアのテレメトリを調べる

データ ストアをインストルメント化して、アクティビティの低レベルの詳細をキャプチャします。 サンプル アプリケーションでは、データ アクセス統計は、 PurchaseOrderHeader テーブルと MonoLog テーブルの両方に対して実行される大量の挿入操作を示しています。

サンプル アプリケーションのデータ アクセス統計を示すグラフ。

リソースの競合を特定する

この時点で、アプリケーションが意図したリソースにアクセスするポイントに焦点を当てて、ソース コードを確認できます。 次のような状況を探します。

  • 論理的に分離されたデータは、同じストアに書き込まれます。 ログ、レポート、キューに登録されたメッセージなどのデータは、ビジネス情報と同じデータベースに保持しないでください。
  • データ ストアの選択と、リレーショナル データベース内の大きな BLOB や XML ドキュメントなどのデータの種類が一致しません。
  • 同じストアを共有するさまざまな使用パターンを持つデータ。 たとえば、高書き込みデータと低読み取りデータが、低書き込みデータと高読み取りデータと共に格納されます。

ソリューションを実装し、結果を確認する

この例では、別のデータ ストアにログを書き込むようアプリケーションを更新します。 次のグラフは、ロード テストの結果を示しています。

Polyglot コントローラーを使用したロード テストのパフォーマンス結果を示すグラフ。

スループットのパターンは以前のグラフに似ていますが、パフォーマンスのピークが 1 秒あたり約 500 要求高くなるポイントです。 平均応答時間は、わずかに低くなります。 ただし、これらの統計は完全なストーリーを伝えるわけではありません。 ビジネス データベースのテレメトリは、DTU 使用率が 100%ではなく、約 75%でピークであることを示しています。

Polyglot シナリオでのデータベースのリソース使用率を示す Azure クラシック ポータルのデータベース モニターを示すグラフ。

同様に、ログ データベースの最大 DTU 使用率は約 70%に達します。 データベースは、システムのパフォーマンスの制限要因ではなくなりました。

Polyglot シナリオでのログ データベースのリソース使用率を示す Azure クラシック ポータルのデータベース モニターを示すグラフ。