Skip to content

MS_CloudApplicationArchitectureGuide

nishi_74322014 edited this page Sep 12, 2026 · 3 revisions

クラウド アプリケーション アーキテクチャ ガイド

概要

  • 参考から目次を抜いて体系化した。
  • 結構、網羅が出来て来た(オンデマンドで追記予定)。

補足(3 ページの棲み分け): Azure Architecture Center の内容は
本 Wiki では次の 3 ページに分かれている。混同しやすいので整理しておく。

ページ 扱うもの 粒度
Azure Well-Architected Framework 評価の観点(5 本の柱) 判断基準
本ページ 選択肢の体系(スタイル・原則・技術選定・ベスト プラクティス) 設計手順
参照アーキテクチャ 具体的な構成例 実装の出発点

さらに、個々の実装手法は
クラウド設計パターンにまとまっている。

詳細

以下のような立て付けになっている。

アーキテクチャ スタイル

ビッグ コンピューティング

Azure Batch (HPC) 推しらしい。

ビッグ データ

イベントドリブン アーキテクチャ

  • パブリッシュ/サブスクライブ
  • イベント ストリーム モデル
    • イベントがログに書き込まれる。
    • クライアントはいつでも参加でき、イベントを再生
    • ストリーム内でクライアントの位置を進めるのは、クライアントの役割

補足(この 2 つは別物): 同じ「イベント」でも、
メッセージング型(Pub/Sub)とイベント ストリーム型
性質がまったく異なる。ここを混同すると製品選定を誤る。

Pub/Sub(メッセージ) イベント ストリーム(ログ)
イベントの寿命 消費されたら消える 保持期間まで残る
位置の管理 ブローカー側 クライアント側(オフセット)
再生 基本的に不可 可能(過去から読み直せる)
後から参加 過去分は受け取れない 過去分から読める
Azure の例 Service Bus、Event Grid Event Hubs(Kafka 互換)

「クライアントの位置を進めるのはクライアントの役割」という
本文の一文が、この違いの核心を突いている。

マイクロサービス

  • 真面目にやると沼。
  • SOA の REST WebAPI 版(雑)

補足(「真面目にやると沼」は正しい): この身も蓋もない一言は
実務上きわめて重要な指摘である。マイクロサービスは
技術の選択ではなく組織と運用の選択であり、
分割した瞬間に次がすべて必要になる。

単一アプリなら不要だったもの
サービス間通信の失敗処理(Polly、再試行、サーキット ブレーカー)
分散トランザクションの回避(Saga、補正トランザクション、結果整合性)
分散トレーシング(1 リクエストが何十サービスを跨ぐ)
サービス ディスカバリ、API ゲートウェイ
サービスごとの CI/CD とバージョン互換管理
データの重複と同期(DB を共有できない)

したがって現在の一般的な指針は
**「モノリスから始めて、必要になった部分だけ切り出す」**である
(モジュラー モノリス)。
「SOA の REST 版」という要約も、
粒度と自律性の度合いが違うだけという意味では的を射ている。

n 層アプリケーション

アプリケーションを論理層と物理層に分離

補足: 従来型の分割であり、
アプリケーション・アーキテクチャで扱う
物理 2 層/3 層の議論がそのまま当てはまる。
クラウドへの移行(リフト&シフト)で最も選ばれる形でもある。

Web キューワーカー

  • Web ロール、Worker ロール
  • 必要に応じて、キュー

補足: 「Web ロール/Worker ロール」は
Azure Cloud Services(クラシック)の用語である
(同サービスは 2024 年 8 月に提供終了)。
ただし構成としての Web-Queue-Worker は現役
であり、
現在は次のように実装する。

役割 現在のサービス
Web App Service、Container Apps
キュー Storage Queue、Service Bus
Worker Functions、WebJobs、Container Apps Jobs

重い処理をキュー経由で後段に逃がすという形は、
応答時間の確保と負荷平準化の両方に効く、最も費用対効果の高い構成である。

設計原則

自動修復機能の設計

すべてを冗長化

調整を最小限に抑える

補足(「調整」= coordination がクラウドで最も高くつく): この原則の原文は
"Minimize coordination" である。
インスタンス間で合意を取る処理(ロック、分散トランザクション、
順序保証)は、台数を増やすほど待ちが増えるため、
スケールアウトの効果を打ち消してしまう。

【調整あり】 台数を増やす → 調整のオーバヘッドが増える → 頭打ち
【調整なし】 台数を増やす → そのままスループットが伸びる

したがってクラウドでは、ACID を諦める代わりに

  • 楽観排他(衝突は稀と仮定して、起きたら弾く)
  • 冪等性(同じ操作を何度実行しても同じ結果)
  • 結果整合性(今すぐ一致していなくてよい)
  • 補正トランザクション(ロールバックの代わりに打ち消す操作)

という手段で置き換える。
特に冪等性は、再試行を前提とする以上
避けて通れない要件になる(Polly)。

スケールアウトのための設計

垂直方向・水平方向にスケールできるように設計

  • 垂直方向
    システム、アプリで構成する。
    • ボトルネックの特定、ワークロードの分解など。
    • タスクのオフロード(バックグラウンド・ジョブ化)
  • 水平方向
    クラウド機能で構成する。
    • サーバー・ステートレス
    • スケールアウト・スケールイン
    • 自動スケール

補足(ステートレス化が全ての前提): 水平方向の項にある
「サーバー・ステートレス」が、
実はこの節で最も重要な一行である。
サーバがセッション状態を保持していると、

  • スケールアウトしても同じサーバに戻す必要がある(スティッキー セッション)
  • スケールインや再起動で状態が消える

ため、水平方向のスケールが機能しない。
ASP.NET では、セッション状態を
**プロセス外(SQL Server / Redis)**に出すか、
そもそもサーバに持たない設計にする
ASP.NETの状態管理方式)。

パーティション分割による制限の回避

スケール・アップに限界があるので、パーティション分割。

  • システム
    • データベース
    • キューまたはメッセージ バス
    • App Service Web アプリ
  • データベース

操作に合わせた設計

運用チームが必要なツールを得られるようにアプリケーションを設計

管理対象サービスの使用

なるべく、PaaS / FaaS, SaaSを選択。

ジョブに最適なデータ ストアの使用

改良を見込んだ設計

SOA っぽい(疎結合)。

  • 高凝集と疎結合
    • サービスを個別にデプロイ
    • 共通機能を専用のサービスにオフロード
  • ゲートウェイにはドメイン ナレッジを実装しない
    • ドメイン ナレッジをカプセル化
    • オープン インターフェイスを公開
    • 非同期メッセージングを使用
  • クリーン・アーキテクチャ(.NET開発基盤部会 Wiki)的な
    (抽象インフラストラクチャをドメイン ロジックと分離)

ビジネス ニーズに合わせた構築

  • 成長に対応可能な計画とコストの管理
  • 目標復旧時間 (RTO)、目標復旧時点 (RPO)、最大許容停止時間 (MTO)
  • サービス レベル アグリーメント (SLA) とサービス レベル目標 (SLO)
  • 要件
    • 機能要件と非機能要件
    • ワークロード別に分けて要件を判断
  • ビジネス ドメインを中心にアプリケーションをモデル化(DDD)

補足(合成 SLA に注意): 複数のマネージド サービスを
直列に組み合わせると、SLA は掛け算で下がる

App Service(99.95%) × SQL Database(99.99%) × Storage(99.9%) ≒ 99.84%
  → 年間の許容停止時間は 約 14 時間

「各サービスが 99.9% 以上だから全体も 99.9%」は成立しない。
冗長構成(並列)を入れると逆に上がるため、
直列か並列かを意識して合成 SLA を計算する必要がある。

技術選定

コンピューティング サービスの選択

適切なモンを使えと。

データ ストアの選択

適切なモンを使えと。

多言語パーシステンスと言うらしい。

補足(「適切なモンを使え」の判断軸): 突き放した書き方だが、
実際の判断軸はそれほど多くない。

問い 分岐
強い整合性が要るか 要る → RDBMS。要らない → NoSQL も可
クエリの形は決まっているか 決まっている → キー値/ドキュメント。自由 → RDBMS
スキーマは変化するか よく変わる → ドキュメント DB
想定データ量とスループット 単一インスタンスの限界を超えるか
関連(JOIN)が中心か 中心 → RDBMS、グラフ

なお、「多言語パーシステンス」を字義どおりに実践すると
運用対象の DB が増えて破綻しやすい。
既定は RDBMS、明確な理由があるものだけ別の DBという
保守的な運用が現実的である。

負荷分散サービスの選択

負荷分散については、NLBの項が参考になる。
(NLB を使えとは言っていない)

補足(Azure の負荷分散サービスの選び分け): 4 種類あり、
OSI 参照モデルのどの層で振るか
グローバルかリージョン内かで整理できる。

サービス 範囲 主な用途
Traffic Manager DNS グローバル リージョン間の振り分け・DR
Front Door L7(HTTP) グローバル CDN + WAF + グローバル負荷分散
Application Gateway L7(HTTP) リージョン内 URL パス ベース振り分け、WAF、SSL 終端
Load Balancer L4(TCP/UDP) リージョン内 非 HTTP を含む一般的な分散

メッセージング サービスの選択

色々あるらしい。

  • Azure Service Bus
  • Event Grid
  • Event Hubs

補足(3 つの使い分け): 名前が似ているが役割は明確に違う。

サービス 種別 特徴 典型的な用途
Service Bus メッセージ 順序保証、トランザクション、デッド レター、FIFO 業務処理の確実な受け渡し
Event Grid イベント通知 軽量、Push 配信、Azure リソースの変化に反応 リソース作成をトリガに処理を起動
Event Hubs イベント ストリーム 大量取り込み、再生可能、Kafka 互換 テレメトリ・ログの収集

判断のこつは、
**「取りこぼしたら業務が成立しないか(メッセージ)」**と
**「大量に流れてくる事実の記録か(イベント)」**の区別である。

ベスト・プラクティス

API 設計

  • WebAPI > REST
  • 非同期操作CIBAのような)
  • データ処理
    (ネットワーク帯域幅と処理能力の有効活用)
    • フィルター or ページング処理
    • HATEOAS
    • バイナリ リソースの部分的な応答

API 実装

自動スケール

水平方向のスケーリング

補足(自動スケールは万能ではない): 実務で問題になるのは
スケールが間に合わないケースである。

  • VM やインスタンスの起動には数分かかる
    数十秒で立ち上がる急激なスパイクには追随できない。
  • 判定に使うメトリック(CPU 等)は遅行指標であり、
    混雑してから増え始める。

対策としては、

手段 内容
キューによる平準化 スパイクをキューで吸収し、Worker は一定速度で処理
予測に基づくスケール 業務のピーク時刻が既知ならスケジュール スケールを併用
事前ウォームアップ 最小インスタンス数を高めに設定
スケールインの緩和 クールダウンを長めにし、フラッピングを防ぐ

また、後述のチューニングの節にあるとおり、
自動スケールは根本の問題を隠す副作用がある
(遅いクエリを台数で押し切ってしまう)。

バックグラウンド ジョブ

キャッシュ

  • 注意点
    • 高可用性の実装、スケーラビリティ・パフォーマンスの向上
    • コンカレンシーの管理、最終的な整合性
      • データをキャッシュするタイミングを決める
      • データを効率的にキャッシュする方法を決める
      • 非常に動的なデータをキャッシュする
      • キャッシュ内のデータの有効期限を管理する
      • クライアント側キャッシュ内のデータを無効にする
  • Redis Cache(.NET開発基盤部会 Wiki)

補足(キャッシュの難所は「消し方」): 上の注意点が
有効期限・無効化に集中しているとおり、
キャッシュで難しいのは載せ方ではなく捨て方である。

問題 内容と対策
キャッシュ スタンピード 期限切れの瞬間に全リクエストが DB に殺到する。有効期限をずらす(ジッター)、再生成を 1 本に絞る
古いデータの表示 更新時に明示的に無効化する(write-through / write-behind)
キャッシュ障害時の雪崩 キャッシュが落ちると全負荷が DB へ。DB 側が耐えられるかを確認しておく
何でも載せる ヒット率が下がりメモリを浪費する。参照が多く更新が少ないものに絞る

Content Delivery Network (CDN)

  • ルーティングとバージョン管理
  • キャッシュ制御
  • セキュリティ
  • CDN フォールバック

データのパーティション分割

補足(パーティション キーの選択が全てを決める): 水平分割では
キーの選び方を後から変えるのが極めて困難である
(全データの再配置が必要になる)。選定時の観点は次のとおり。

観点 内容
均等に分散するか 偏るとホット パーティションが生まれ、そこだけ飽和する
クエリがキーを含むか 含まないと全パーティションへの問い合わせ(fan-out)になる
跨ぐトランザクションが要るか 要るなら分割位置が誤っている可能性が高い
時系列キーの罠 日付をキーにすると最新パーティションに書き込みが集中する

SQL Server のパーティション
単一インスタンス内の分割であり、
ここでいうシャーディング(インスタンスを跨ぐ分割)とは
目的が異なる点にも注意する
SQL Server の Elastic Scale とプール)。

データのパーティション分割戦略 (サービスごと)

  • Azure SQL Database のパーティション分割
  • Azure Table Storage のパーティション分割
  • Azure Blob Storage のパーティション分割
  • Azure Queue Storage のパーティション分割
  • Azure Service Bus のパーティション分割
  • Cosmos DB のパーティション分割
  • Azure Search のパーティション分割
  • Azure Cache for Redis のパーティション分割
  • Azure Service Fabric のパーティション分割
  • Azure Event Hubs のパーティション分割

デプロイ スタンプ

  • データ ストアを含め、アプリケーション コンポーネントの複数の独立したコピーをデプロイする。
  • 個々のコピーは "スタンプ" と呼ばれ、"サービス ユニット" または "スケール ユニット" と呼ばれる場合もある。
  • このアプローチにより、
    • 顧客データを分離でき、
    • ソリューションのスケーラビリティが向上し、
    • インスタンスを複数のリージョンにデプロイすることが可能となる。
  • 自動化された完全に反復可能なデプロイ プロセスを使用する

補足: マルチテナント SaaS で
テナントごと(または一定数のテナントごと)に一式を丸ごと複製する方式である。
分離とスケールを同時に得られる一方、
スタンプ数だけ運用対象が増えるため、
「自動化された完全に反復可能なデプロイ」が
努力目標ではなく前提条件になる
クラウドのインフラ自動化)。

監視と診断

  • 正常性の監視
  • 可用性の監視
  • パフォーマンスの監視
  • セキュリティの監視
  • SLA の監視
  • ユーザー操作の監査
  • 利用状況の監視
  • 問題追跡
  • 操作のトレース
  • リリースのデバッグ
  • 監視と診断のパイプライン
  • 監視と診断のデータ ソース
  • アプリケーションのインストルメント化
  • データの収集と保存
  • データの分析と問題の診断
  • データの視覚化とアラートの生成

補足(分散システムでは「監視」から「可観測性」へ): 単一サーバであれば
ログを見れば済んだが、リクエストが複数サービスを跨ぐと
どこで遅くなったのかがログからは分からない
そこで、次の 3 本を揃えるのが現在の標準的な考え方である。

内容 Azure での実装
メトリック 数値の時系列(CPU、応答時間、キュー長) Azure Monitor
ログ 事象の記録 Log Analytics
トレース 1 リクエストの経路と各区間の所要時間 Application Insights(分散トレース)

特に分散トレースは、
相関 ID を全サービスに引き回すことで
「A → B → C のうち B が遅い」を可視化する。
これが無いと、後述の「カスケード エラー」の切り分けができない。
現在は OpenTelemetry が標準規格となり、
Application Insights もこれに準拠している。

特定のサービスの再試行ガイダンス

一時的な障害の処理

  • 標準の再試行機構が存在するかどうかを調べる。
  • 操作を再試行するのが妥当かどうかを判断する。
  • 適切な再試行回数と間隔を決める。
  • アンチパターンを避ける。
  • 再試行の戦略と実装をテストする。
  • 再試行ポリシーの構成を管理する。
  • 一過性の障害と一過性ではない障害を記録、追跡する。
  • 絶えず失敗する操作に対処する。

補足(再試行は「やり過ぎると障害を悪化させる」): 一覧の
「アンチパターンを避ける」の中身が実務では最重要である。

アンチパターン 何が起きるか
多層での再試行 ライブラリ・アプリ・ゲートウェイが各 3 回 → 実際は 27 回。負荷が指数的に増える
固定間隔での再試行 全クライアントが同時に再試行し、回復直後に再び潰す(thundering herd)
再試行すべきでないものを再試行 認証エラー・不正な入力(4xx)は何度やっても失敗する
冪等でない操作の再試行 二重登録・二重課金
上限が無い 障害が終わらない

正しい形は
指数バックオフ+ジッター(乱数)+上限+サーキット ブレーカーである。
サーキット ブレーカーは、失敗が続いたら
一定時間まったく呼びに行かないことで
相手の回復を待ち、自分側のスレッドも守る。
.NET では Polly がこれらを提供する。

チューニング

  • テレメトリでメトリックを収集できるようコードをインストルメント化する。
  • 平均値によって、外れ値が解らなくなる可能性があるので、
    90/95/99 パーセンタイル値を閾値にも監視する。
  • 一度に 1 つのボトルネックに取り組む
    (ボトルネックを取り除くと、次の別のボトルネックが明らかになる)
  • エラーと再試行は、パフォーマンスに大きな影響を与える可能性がある。
  • 並列、分散化できる可能性を探す(パーティション分割)。
    • 1 つの操作を包括的にエンドツーエンドで把握するのは困難になる。
    • 一貫性のあるビューを取得するにはログとメトリックを 1 か所で集計する。
    • 自動スケールは、
      • 元の問題が解らなくなる可能性がある。
      • また、スケールアウト・スケールインの閾値も解らなくなる。
    • カスケード エラー
      • エラーが連鎖して根本原因とは
        異なるコンポーネントでシグナルが現れる
      • 上流のエラーが原因で下流で障害が発生する。

移行メモ(体裁): 原典の「90/95/99 パーセンタイルパーセンタイル値」は
「パーセンタイル」が重複していたため修正した。
また「基の問題」は「元の問題」とした。

補足(「一度に 1 つのボトルネック」の意味): これは手順の指示であると同時に、
性能問題の性質そのものを述べている。
システムの処理速度は最も遅い箇所で決まるため、
そこを直すまで他をいくら速くしても全体は変わらない。
そして直した瞬間、次に遅い箇所が新しい上限として現れる

【改善前】 CPU:30%  DB:95% ← ここが上限   NW:20%
【DB改善後】CPU:85% ← 新しい上限  DB:40%   NW:25%

したがって、

  • 同時に複数を直さない(どれが効いたか分からなくなる)
  • 1 つ直すたびに測り直す
    JmeterによるWebアプリの負荷テスト
  • 改善目標に達したらそこで止める(際限が無い)

という進め方になる。
オンプレミス/単体システムでの同じ議論は
性能問題のポイント
因果関係の分析例を参照。

分散トランザクション

https://docs.microsoft.com/ja-jp/azure/architecture/performance/distributed-transaction

複数のバックエンド サービス

https://docs.microsoft.com/ja-jp/azure/architecture/performance/backend-services

イベントのストリーミング

https://docs.microsoft.com/ja-jp/azure/architecture/performance/event-streaming

アンチ・パターン

  • ビジー状態のデータベース
  • ビジー状態のフロント エンド
  • 頻度の高い I/O
  • 余分なフェッチ
  • 不適切なインスタンス化
  • モノリシック永続化
  • キャッシュなし
  • 同期 I/O

補足(各アンチパターンの中身): 名称だけでは分かりにくいため補足する。
いずれもクラウド固有ではなく、従来から性能問題の定番である。

アンチパターン 内容 対処
ビジー状態のデータベース ロジックを DB(ストアド)に寄せ過ぎ、スケールしにくい層に負荷が集中 アプリ層に戻す
ビジー状態のフロント エンド Web 層で重い処理を同期実行し、要求を捌けなくなる キュー+ Worker に逃がす
頻度の高い I/O(Chatty I/O) 細かい呼び出しの多発。ラウンド トリップの累積が支配的になる まとめて取得する
余分なフェッチ(Extraneous Fetching) SELECT * や全件取得後にアプリで絞る 必要な列・行だけ取る
不適切なインスタンス化 HttpClient 等を毎回 new する(ソケット枯渇の原因) 使い回す(IHttpClientFactory
モノリシック永続化 全データを 1 つのストアに押し込む 特性ごとに分ける
キャッシュなし 同じ結果を毎回作り直す キャッシュを入れる
同期 I/O I/O 待ちでスレッドを占有し、スレッド プールが枯渇 async/await

このうち Chatty I/O同期 I/O
.NET アプリで特に頻出する。
前者は ADO.NET・ORM の使い方
ADO.NET vs ORM)、
後者は初回が遅い!などと併せて理解しておきたい。

サービス毎

参考

Microsoft Docs

アーキテクチャ スタイル

https://docs.microsoft.com/ja-jp/azure/architecture/guide/architecture-styles/

10 の設計原則

https://docs.microsoft.com/ja-jp/azure/architecture/guide/design-principles/

技術選定

https://docs.microsoft.com/ja-jp/azure/architecture/guide/technology-choices/

ベスト・プラクティス

https://docs.microsoft.com/ja-jp/azure/architecture/best-practices/

チューニング

https://docs.microsoft.com/ja-jp/azure/architecture/performance/

その他

多言語パーシステンス

HATEOAS

補足(HATEOAS は普及しなかった): HATEOAS は REST の
成熟度モデル(Richardson Maturity Model)のレベル 3にあたり、
応答に次に取り得る操作のリンクを含めることで
クライアントが URL を組み立てずに済む、という考え方である。

ただし実際にはほとんど普及しなかった
クライアント側にリンクを解釈する仕組みが必要な割に
得られる疎結合が限定的だったためで、
現在の Web API は**レベル 2(リソース+ HTTP メソッド)**に
OpenAPI による仕様記述を組み合わせる形が主流である
WebAPIREST)。


Tags: 移行, アーキテクチャ, クラウド系開発

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally