🦜

精読「ソフトウェアアーキテクチャの基礎」(2)

2025/01/15に公開



ソフトウェアアーキテクチャの基礎
本書は、ソフトウェア開発におけるアーキテクチャ設計の基本原則と実践的な知識を体系的に解説した一冊です。初心者から中級者まで、システム設計の基礎を固めたい人に最適なガイドです。アーキテクトだけでなく、チームリーダーや開発者にも役立つ内容が詰まっています。

関連記事

アーキテクチャスタイル・基礎

アーキテクチャスタイルはシステムの全体的な構造を定義し、アーキテクチャパターンはその中での具体的な解決策を提供する。アーキテクトはスタイルのトレードオフを理解し、効果的な決定を下す必要がある。

アーキテクチャスタイルは、コンポーネント間の関係を定義し、アーキテクチャ特性をカバーする。これらのスタイルは、デザインパターンのように経験豊富なアーキテクト同士の共通の表現として機能する。アーキテクチャスタイルには、トポロジーやアーキテクチャ特性、メリット・デメリットが含まれ、アーキテクトはその詳細に精通している必要がある。

基礎的なパターン

基礎的なパターンでは、重要なアーキテクチャパターンが紹介されている。

  • 巨大な泥団子: 構造がなく無秩序なシステムで、変更が難しく問題を引き起こす。
  • ユニタリーアーキテクチャ: 初期の一元的なシステムで、現代では関心事を分離する必要がある。
  • クライアント/サーバー: システムをフロントエンドとバックエンドに分け、時代とともに進化(例: デスクトップ+データベース、ブラウザ+Webサーバー、3層アーキテクチャ)。

モノリシックアーキテクチャと分散アーキテクチャ

アーキテクチャはモノリシックと分散型に分類され、分散アーキテクチャは性能やスケーラビリティが優れている一方で、いくつかの誤信があることに注意が必要。

  1. ネットワークは信頼できる:ネットワークは信頼できず、通信の障害やタイムアウトが発生する可能性がある。
  2. レイテンシーがゼロ:分散アーキテクチャでは、ネットワーク経由の通信にはレイテンシーが必ず存在する。
  3. 帯域幅は無限:サービス間通信で帯域が消費され、通信の増加によりパフォーマンスに影響が出る。
  4. ネットワークは安全:分散アーキテクチャではセキュリティの対策が重要で、サービス間通信におけるセキュリティリスクが増加する。
  5. トポロジーは変わらない:ネットワークのトポロジーは常に変化し、変化に対応できるように設計が必要。
  6. 管理者は一人だけ:ネットワーク管理者が複数存在するため、管理者間の協力が重要。

これらの誤信に対処するためには、設計時にこれらの課題を考慮し、適切な対応策を講じることが求められる。

レイヤードアーキテクチャ

レイヤードアーキテクチャは、シンプルさや親しみやすさ、コストの低さから、最も一般的なアーキテクチャスタイルの一つ。このアーキテクチャは、システムを異なる層(UI、バックエンド、ルール、DBA)に分け、それぞれの層が特定の役割を持つ。多くの組織では、この構造が自然に組織内のチームに一致し、システム設計が容易になる。しかし、レイヤードアーキテクチャは、暗黙のアーキテクチャアンチパターンや偶発的なアンチパターンに陥ることもある。特に、アーキテクチャスタイルを意識せずに開発を始めた場合、レイヤードアーキテクチャが選ばれがち。

トポロジー

レイヤードアーキテクチャは、システムをプレゼンテーション層、ビジネス層、永続化層、データベース層などのレイヤーに分け、それぞれのレイヤーが特定の役割を果たす。物理的なデプロイメントには複数のパターンがあり、各レイヤーは独立して、もしくは統合されてデプロイされる。このアーキテクチャは、技術的役割で分割され、ドメイン駆動設計とは相性が悪いことがある。

層の分断

レイヤードアーキテクチャでは、各レイヤーが閉鎖レイヤーか開放レイヤーに分かれる。閉鎖レイヤーでは、リクエストは順番にレイヤーを通過しなければならず、開放レイヤーでは、リクエストが他のレイヤーをバイパスできるようになる。層の分離は、レイヤー間で影響を与えないようにする重要な考え方で、プレゼンテーション層が直接永続化層にアクセスできないようにする。これにより、変更の影響を最小化し、アーキテクチャの柔軟性と保守性が向上する。

レイヤーの追加

閉鎖レイヤーは「層の分離」を容易にし、変更を分離するのに役立つが、開放レイヤーにする方が適切な場合もある。例えば、ビジネス層に共有オブジェクトが含まれている場合、プレゼンテーション層からそれにアクセスするのは管理が難しくなる。この問題を解決するために、新たにサービス層を追加することでビジネス層を閉じ、サービス層を開放レイヤーにすることで、ビジネス層が永続化層に直接アクセスできるようにする。開放と閉鎖レイヤーを適切に活用することで、アーキテクチャの管理が容易になり、テストや保守の難易度を下げることができる。

その他の考慮事項

レイヤードアーキテクチャは、多くのアプリケーションにとって最適な出発点ですが、アーキテクチャシンクホールというアンチパターンに注意が必要。このパターンは、リクエストがレイヤー間でパススルーされ、ビジネスロジックが実行されない場合に発生する。例えば、プレゼンテーション層からビジネス層、さらにルールレイヤーへとリクエストが渡り、何も処理されずに戻ってくることがある。これにより、不必要なオブジェクトのインスタンス化やメモリ消費、パフォーマンスの低下が生じる。

シンクホールが発生しているかを判断するには、リクエストのパーセンテージを分析する。80対20ルールに従い、リクエストの20%だけがシンクホールであれば問題ないが、80%がシンクホールになっている場合、レイヤードアーキテクチャが適切でない可能性がある。シンクホールを解決するために、すべてのレイヤーを開放レイヤーにする方法もあるが、その場合、アーキテクチャ内の変更管理が難しくなるというトレードオフがある。

このアーキテクチャスタイルを採用する理由

レイヤードアーキテクチャは、小規模でシンプルなアプリケーションやWebサイトに適しており、予算と時間に制約がある状況での出発点として優れている。開発者にとってシンプルで親しみやすく、低コストで開発が容易ですが、アプリケーションが大きくなると、保守性やアジリティ、テストの容易性に悪影響を及ぼす可能性があるため、大規模なシステムには他のモジュール化されたアーキテクチャが推奨される。

アーキテクチャ特性の評価

アーキテクチャ特性 星評価
分割タイプ 技術
量子数 1
デプロイ容易性
弾力性
進化性
耐障害性
モジュール性
全体的なコスト ☆☆☆☆☆
パフォーマンス ☆☆
信頼性 ☆☆☆
スケーラビリティ
シンプルさ ☆☆☆☆☆
テスト容易性 ☆☆

レイヤードアーキテクチャの特性評価では、コストとシンプルさが強みとされ、モノリシックな性質が複雑さを減少させる。しかし、アーキテクチャが大きくなると、デプロイやテストの容易性が低下し、デプロイ頻度やリスクが増す。信頼性は中程度、弾力性とスケーラビリティは低いと評価され、モノリスの特性が影響している。パフォーマンスも制約があり、高パフォーマンスを目指すには追加の努力が必要。また、耐障害性が低く、クラッシュ時の回復時間が長くなることが可用性に影響を与える。

パイプラインアーキテクチャ

パイプラインアーキテクチャは、機能を個別のパーツに分割する基本スタイルで、UnixシェルやMapReduceに見られる。関数型プログラミングとも類似性があり、ビジネスアプリケーションにも使用可能。

トポロジー

パイプラインアーキテクチャは、パイプとフィルターから構成される。

  • パイプ:フィルター間の一方向通信チャンネル。パフォーマンス向上のため、一方向かつポイントツーポイントでデータを流す。
  • フィルター:自己完結型でステートレスな要素で、1つのタスクを処理。主な種類はプロデューサー、トランスフォーマー(変換)、テスター、コンシューマー。

このアーキテクチャはシンプルで、構成の再利用を促進する。

事例

パイプラインアーキテクチャは、シンプルな一方通行の処理に使われ、EDIツールやETLツール、ビジネスプロセスオーケストレーションで活用される。例えば、Apache Kafkaを使った事例では、サービス情報をキャプチャし、複数のフィルター(テスターやトランスフォーマー)を通してデータを処理し、最終的にデータをMongoDBに永続化する。このアーキテクチャは拡張性が高く、新しいメトリクスを追加するのも容易。

アーキテクチャ特性の評価

アーキテクチャ特性 星評価
分割タイプ 技術
量子数 1
デプロイ容易性 ☆☆
弾力性
進化性 ☆☆☆
耐障害性
モジュール性 ☆☆☆
全体的なコスト ☆☆☆☆☆
パフォーマンス
信頼性 ☆☆☆
スケーラビリティ
シンプルさ ☆☆☆☆☆
テスト容易性

パイプラインアーキテクチャは、アプリケーションロジックをフィルター(プロデューサー、テスター、トランスフォーマー、コンシューマー)に分割し、モノリシックなデプロイメントで実装されるため、シンプルで低コストな構築と維持が可能。モジュール性により、フィルターの変更や置き換えが容易で、他の部分に影響を与えない。

デプロイやテストの容易さは平均的であり、モノリス特有のデプロイ頻度やリスク、テストの課題はある。信頼性は中程度で、分散アーキテクチャが持つネットワーク課題がないため。しかし、弾力性とスケーラビリティは低く、特にモノリスであるため、スケールの限界がある。耐障害性も欠如しており、メモリ不足などでアプリケーション全体が影響を受けやすく、可用性にも影響が出る可能性がある。

マイクロカーネルアーキテクチャ

マイクロカーネルアーキテクチャ(プラグインアーキテクチャとも呼ばれる)は、数十年前に登場し、現在でも広く利用されているアーキテクチャスタイル。このスタイルは、製品ベースのアプリケーションに適しており、パッケージ化された単一のモノリシックデプロイメントとして提供され、サードパーティ製品として顧客環境にインストールされることが一般的。また、カスタムビジネスアプリケーションにも広く使用されている。

トポロジー

マイクロカーネルアーキテクチャは、コアシステムとプラグインコンポーネントから成るアーキテクチャで、拡張性と柔軟性を提供する。コアシステムは基本的な機能のみを提供し、アプリケーションのロジックや処理は独立したプラグインコンポーネントに分けられる。これにより、処理を簡素化し、保守性やテスト容易性が向上する。プラグインはランタイムで追加・削除可能で、システムの拡張が容易になる。プラグイン間の通信はポイントツーポイントで行われ、疎結合の実現が可能。

レジストリ

レジストリは、コアシステムが利用可能なプラグインやその接続方法を管理するための仕組み。プラグイン名やデータコントラクト、接続プロトコルなどの情報を保持する。シンプルなマップ構造から、Apache ZooKeeperやConsulのような複雑なツールを使うこともある。これにより、システムは動的にプラグインを発見し、管理できる。

コントラクト

プラグインとコアシステム間のコントラクトは、動作やデータを定義する。標準コントラクトとカスタムコントラクトがあり、サードパーティ製のプラグインにはアダプターが必要。例えば、電子機器リサイクルシステムでは、査定レポートや再販フラグなどを返すインターフェイスが使われ、コアシステムはこれを表示する。

事例とユースケース

マイクロカーネルアーキテクチャは、EclipseやJira、Jenkinsなどのツールに使われており、大規模なビジネスアプリケーションにも適用可能。例えば、保険金請求処理では、各管轄区域のルールを独立したプラグインに分け、変更をシステム全体に影響なく行える。また、税務申告書作成ソフトでは、フォームの変更をプラグインコンポーネントとして分離し、リスクを抑えた改修を可能にする。

アーキテクチャ特性の評価

アーキテクチャ特性 星評価
分割タイプ ドメインと技術
量子数 1
デプロイ容易性 ☆☆☆☆
弾力性
進化性 ☆☆☆☆
耐障害性
モジュール性 ☆☆☆☆
全体的なコスト ☆☆☆☆☆
パフォーマンス ☆☆☆☆
信頼性 ☆☆☆☆
スケーラビリティ
シンプルさ ☆☆☆☆
テスト容易性 ☆☆☆☆

マイクロカーネルアーキテクチャの強みはシンプルさとコスト効率だが、スケーラビリティや耐障害性に課題がある。ドメインや技術で分割でき、カスタマイズ性や拡張性に優れている。テストやデプロイが容易で、プラグインの追加・削除が簡単。パフォーマンスも良好で、不要な機能を除外することで速度向上が可能。

サービスベースアーキテクチャ

サービスベースアーキテクチャ(SBA)は、マイクロサービスアーキテクチャのハイブリッド型で、柔軟性が高く、実用的なアーキテクチャスタイルとして広く採用されている。分散型のアーキテクチャだが、マイクロサービスやイベント駆動アーキテクチャのような複雑さやコストは避けることができ、ビジネスアプリケーションで非常に人気がある。

トポロジー

サービスベースアーキテクチャ(SBA)は、分散型で粗い粒度のサービスを個別にデプロイし、モノリシックなデータベースを共有する。サービス間の通信にはRESTやRPCが使用され、ユーザーインターフェイスはAPI層を通じてアクセスする。サービス数は4~12で、データベース変更の管理には注意が必要。

トポロジーの種類

サービスベースアーキテクチャには柔軟なトポロジーがあり、以下の方法で構成できる

  • ユーザーインターフェイス分割:モノリシックなUIをドメインごとに分割可能。
  • データベース分割:データベースをドメインサービスごとに分割し、重複を避ける。
  • API層追加:ユーザーインターフェイスとサービス間にAPI層を追加し、共通の横断的要件を管理。

これにより、システムは柔軟で効率的に設計できる。

サービスの設計と粒度

サービスベースアーキテクチャでは、ドメインサービスは粗い粒度で設計され、APIファサード層がビジネス要求をオーケストレーションする。サービスの粒度が粗いと、データ整合性が保ちやすいが、変更時の影響範囲が広くなる。一方、マイクロサービスアーキテクチャでは、粒度が細かく、変更が他のサービスに与える影響が少ない。

データベース分割

サービスベースアーキテクチャでは、通常、単一のモノリシックなデータベースを使用するが、テーブルスキーマの変更が他のサービスに影響を与える可能性がある。この問題を解決するため、データベースを論理的に分割し、各ドメインサービスごとに異なる共有ライブラリを使う方法が有効。これにより、特定のドメインに関連する変更が他のサービスに影響を与えなくなり、データベースの管理が簡素化される。

アーキテクチャ特性の評価

アーキテクチャ特性 星評価
分割タイプ ドメイン
量子数 1以上
デプロイ容易性 ☆☆☆☆
弾力性 ☆☆
進化性 ☆☆☆☆
耐障害性 ☆☆☆☆
モジュール性 ☆☆☆☆☆
全体的なコスト ☆☆☆☆
パフォーマンス ☆☆☆☆
信頼性 ☆☆☆☆
スケーラビリティ ☆☆☆☆
シンプルさ ☆☆☆
テスト容易性 ☆☆☆☆

サービスベースアーキテクチャ(SBA)は、システムをビジネスドメインごとに分割して独立したサービスとしてデプロイする。これにより、アジリティ、テスト容易性、耐障害性などが向上する。各サービスは他のサービスに影響を与えず、変更が迅速に行える。スケーラビリティや弾力性に関しては、マイクロサービスに比べて劣りますが、シンプルでコスト効率が高い。

このアーキテクチャスタイルがふさわしいとき

サービスベースアーキテクチャ(SBA)は、分散アーキテクチャの中でも高い柔軟性と実用性を持っている。強力なアーキテクチャが必要ない企業に適しており、ドメイン駆動設計に自然に適応している。粒度の粗いサービスは、ACIDトランザクションを維持でき、他の分散アーキテクチャに比べてトランザクション管理が容易。また、粒度の調整を容易にし、オーケストレーションやコレオグラフィの複雑さを回避し、適切なモジュール性を保つ。

イベント駆動アーキテクチャ

イベント駆動アーキテクチャ(EDA)は、非同期でイベントに反応する分散型アーキテクチャ。リクエストベースモデルが同期的な処理を行うのに対し、EDAはイベントに基づいて非同期的にアクションを実行する。EDAは単体でも、他のアーキテクチャスタイルと組み合わせても使用できる。

トポロジー

イベント駆動アーキテクチャには、ブローカートポロジーメディエータートポロジーの2種類がある。ブローカートポロジーは、応答性と動的制御が重要な場合に使用され、メディエータートポロジーは、イベント処理のワークフロー制御が求められる場合に使用される。それぞれの特性を理解し、状況に応じて選択することが重要。

ブローカー

ブローカートポロジーは、中央のメディエーターなしで軽量なメッセージブローカー(RabbitMQやActiveMQなど)を使い、イベント処理を分散させる方式。イベントプロセッサーは非同期的に処理を行い、各プロセッサーが独立して動作する。これにより、高いスケーラビリティ、応答性、パフォーマンスを実現するが、エラー処理やワークフロー制御が難しく、再起動や回復性に課題がある。

メディエーター

メディエータートポロジーは、ブローカートポロジーの欠点を解消するためのアーキテクチャで、イベントメディエーターが複数のイベントプロセッサーの調整を行う。イベントメディエーターはイベントの処理ワークフローを管理し、処理イベントを専用のイベントチャンネルに送信。各イベントプロセッサーはそのチャンネルで待機し、処理を行う。

メディエーターは、イベントを処理するためのステップを知っており、複数のメディエーターを使用して、特定のイベントに関連する処理を分担できる。ワークフローが単純であればApache CamelやMule ESB、複雑であればBPELやBPMエンジンを使うことが適している。

非同期の能力

イベント駆動アーキテクチャ(EDA)は、非同期通信を活用し、システムの応答性を向上させる。同期通信では処理に時間がかかりますが、非同期通信ではユーザーの応答時間が短縮される。例えば、コメント投稿の例では、非同期通信によってエンドユーザーはわずか25ミリ秒で投稿完了を確認でき、全体的な処理は3,025ミリ秒で完了する。

しかし、非同期通信の課題はエラー処理。エラー時のフィードバックが難しく、システムの複雑さを増す。適切なエラー処理を設けることが重要。

エラー処理

ワークフローイベントパターンは、非同期ワークフローでのエラー処理を効率化する。エラーが発生すると、イベントコンシューマーは処理を次のメッセージに移し、エラーをワークフロープロセッサーに委譲。修正後、エラーを再処理する。修正できない場合はダッシュボードで手動修正される。例えば、証券取引のエラーが発生した場合、非同期で修正し、処理を続行できる。

データロスの防止

非同期通信でのデータロスを防ぐためには、以下の基本的なテクニックを活用できる。

  • キューへのメッセージ到達問題: メッセージがキューに届かない場合、永続的なメッセージキューを使い、同期送信を行うことで解決できる。これにより、メッセージが物理的に保存され、ブローカーがクラッシュしてもメッセージは復旧できる。

  • イベントプロセッサーのクラッシュ問題: メッセージをキューから取得後にプロセッサーがクラッシュした場合、クライアント応答モードを使用する。これにより、メッセージはキューに残り、再処理が可能。

  • データベースへの永続化問題: メッセージがデータベースに永続化されない場合、ACIDトランザクションを利用してデータの整合性を保証し、メッセージが失われるのを防ぐ。LPS機能で処理完了後にメッセージを削除することもできる。

これらのテクニックを組み合わせることで、イベント駆動アーキテクチャ内でのデータロスを最小限に抑えることができる。

ブロードキャスト能力

イベント駆動アーキテクチャでは、メッセージを複数のサブスクライバーにブロードキャストできる。プロデューサーは受信者や利用方法を気にせず、情報を広く伝えることが可能。これにより、結果整合性や複合イベント処理などに対応できる。

リクエスト・リプライ

リクエスト・リプライメッセージングでは、イベントプロデューサーがリクエストを送信し、リプライキューで応答を待つ形式の同期通信を行う。これには2つの手法がある。

  • 相関ID: リクエストとリプライを関連付けるため、メッセージヘッダーに相関IDを使用する。イベントプロデューサーはリクエストIDを記録し、リプライキューでそのIDと一致する応答を待つ。

  • テンポラリキュー: リクエスト専用の一時的なキューを使い、リクエストが終了したら削除する。相関IDを使わずに、リプライメッセージはそのリクエスト専用のキューに送られる。

相関IDを用いた方法が一般的で、パフォーマンスに優れている。

リクエストベースとイベントベースの間を取る

リクエストベースモデルは構造化データに適し、確実性と管理が求められる。一方、イベントベースモデルは動的なアクションに適し、応答性やスケーラビリティが向上する。イベントベースモデルは、リアルタイム意思決定や柔軟性を提供するが、結果整合性や制御性が低下することがある。

ハイブリッドなイベント駆動アーキテクチャ

イベント駆動アーキテクチャは、他のアーキテクチャスタイルと併用されることが多い。例えば、マイクロサービスやスペースベースアーキテクチャでは、データポンプを使用して非同期にデータを送信し、バックプレッシャーを提供してユーザー応答性を改善する。イベント駆動はオートスケールやサービス間通信でも活用され、ボトルネックの除去やパフォーマンス向上を図る。

アーキテクチャ特性の評価

アーキテクチャ特性 星評価
分割タイプ 技術
量子数 1以上
デプロイ容易性 ☆☆☆☆
弾力性 ☆☆☆
進化性 ☆☆☆☆☆
耐障害性 ☆☆☆☆☆
モジュール性 ☆☆☆☆☆
全体的なコスト ☆☆☆
パフォーマンス ☆☆☆☆☆
信頼性 ☆☆☆☆
スケーラビリティ ☆☆☆☆☆
シンプルさ
テスト容易性 ☆☆

イベント駆動アーキテクチャは、特定のドメインが複数のイベントプロセッサーに分散され、メディエーターやキューを使って結び付けられる。これにより、変更が多くのプロセッサーやメッセージング要素に影響を与える。アーキテクチャ量子は、イベントプロセッサーのデータベースやリクエスト処理に基づき、非同期通信でも同期的に結びつく場合もある。高いパフォーマンス、スケーラビリティ、耐障害性を提供し、特に自動的なロードバランシングでスケーラビリティが確保される。しかし、動的なイベントフローにより、単純性やテスト容易性は低い評価を受ける。一方で、進化性に優れ、機能追加が容易。

スペースベースアーキテクチャ

スペースベースアーキテクチャは、高スケーラビリティと弾力性を提供し、同時接続ユーザー数が変動するアプリケーションに有効。従来のWebアーキテクチャでは、ユーザー負荷が増加するとボトルネックが発生し、スケーリングが困難ですが、スペースベースアーキテクチャはこれを解決する。

一般的なトポロジー

スペースベースアーキテクチャは、タプルスペースを基にしたアーキテクチャで、複数の処理ユニットがメモリ内のデータグリッドを共有し、同期せずにデータをレプリケートすることでスケーラビリティと弾力性を提供する。これにより、中央データベースのボトルネックが解消され、アプリケーションは効率的に拡張可能になる。

主なコンポーネントは次の通り

  • 処理ユニット:アプリケーションロジックを持ち、インメモリデータグリッドを利用。
  • 仮想ミドルウェア:メッセージングやデータ同期を管理。
  • データグリッド:データのレプリケーションと同期を高速に行い、処理ユニット間で共有されます。

これにより、データベースの依存を減らし、柔軟でスケーラブルなシステムを実現する。

データ衝突

レプリケーションキャッシュでのデータ衝突は、複数のサービスインスタンスが同じキャッシュを更新する際に発生する。衝突は、キャッシュAとキャッシュBが互いに更新し合い、最終的に不整合が生じることから起こる。衝突頻度は、インスタンス数、更新レート、キャッシュサイズ、レプリケーションレイテンシーに影響され、計算式を使って予測できる。レプリケーションレイテンシーを減らすことで衝突率を低減できるため、システム設計時にこれらを考慮することが重要。

クラウドとオンプレミス

スペースベースアーキテクチャは、クラウドとオンプレミスの両方でデプロイ可能で、ハイブリッド構成をサポートする。クラウドでアプリケーションを管理し、オンプレミスでデータを保持することで、効果的なデータ同期とトランザクション処理が実現できる。

レプリケーションキャッシュと分散キャッシュ

スペースベースアーキテクチャでは、レプリケーションキャッシュ分散キャッシュが使用される。

  • レプリケーションキャッシュ:高速で耐障害性が高いが、大きなキャッシュや高頻度の更新には向かない。
  • 分散キャッシュ:データ一貫性が高いが、パフォーマンスや耐障害性で劣る。

選択は、データの特性や要求される性能による。

ニアキャッシュの考慮

ニアキャッシュは、インメモリデータグリッドと分散キャッシュをつなぐキャッシュモデルで、フロントキャッシュはフルバッキングキャッシュのサブセットを保持する。しかし、フロントキャッシュの不一致が発生し、他の処理ユニット間でパフォーマンスの不整合を招くため、使用は推奨されない。

実装例

スペースベースアーキテクチャは、高パフォーマンス、高スケーラビリティ、弾力性が求められるアプリケーションに適しており、コンサートチケット販売やオンラインオークションシステムに活用される。

  • コンサートチケット販売システム:人気のコンサートチケットが発売されると、数百人から数千人の同時ユーザーが殺到し、座席の空き状況が迅速に更新される必要がある。中央データベースでは負荷に対応できないため、スペースベースアーキテクチャが最適。
  • オンラインオークションシステム:オークションの開始時に予測できない負荷が発生するが、スペースベースアーキテクチャは、負荷に応じて処理ユニットを増減させ、一貫性を保ちながらパフォーマンスを向上させる。

アーキテクチャ特性の評価

アーキテクチャ特性 星評価
分割タイプ ドメインと技術
量子数 1以上
デプロイ容易性 ☆☆☆☆
弾力性 ☆☆☆☆
進化性 ☆☆☆☆
耐障害性 ☆☆☆☆
モジュール性 ☆☆☆☆
全体的なコスト ☆☆
パフォーマンス ☆☆☆☆☆
信頼性 ☆☆☆☆
スケーラビリティ ☆☆☆☆☆
シンプルさ
テスト容易性

スペースベースアーキテクチャは、弾力性、スケーラビリティ、パフォーマンスに優れ、数百万人の同時ユーザーを処理できるが、テストの難しさや高コストがデメリット。処理ユニットはドメインや技術で分割され、量子はユーザーインターフェイスと処理ユニットの関連で決まる。

オーケストレーション駆動サービス指向アーキテクチャ

オーケストレーション駆動サービス指向アーキテクチャは、その時代の文脈に基づいて理解されるべきであり、外部の影響や組織哲学がアーキテクチャ決定に影響を与えることがある。このアーキテクチャスタイルは、理屈に合っていても、開発プロセスの重要な部分を妨げることがある。

歴史と哲学

オーケストレーション駆動サービス指向アーキテクチャは、1990年代後半の企業の急成長とその成長に対応するための高度なITの需要に応じて登場した。当時、コンピューティングリソースは限られており、多くの企業が分散コンピューティングを必要としていた。この時代、アーキテクトは再利用を重視し、分散アーキテクチャを採用することを強いられ、技術的な分割が進んだが、結果的には悪影響を及ぼした。

トポロジー

オーケストレーション駆動サービス指向アーキテクチャのトポロジーでは、サービスが特定の責任を持つ層として分類されるが、その正確な境界は組織によって異なる。

分類

このアーキテクチャでは、サービスが階層的に分類され、それぞれが異なる責任を持つ。

  • ビジネスサービス: ビジネスドメインの振る舞いを表現するサービス。
  • エンタープライズサービス: 再利用可能な小さなサービスで、ビジネスサービスを構成。
  • アプリケーションサービス: 特定のアプリケーションのための使い捨てサービス。
  • インフラストラクチャサービス: 運用に必要なサービス(監視、認証など)。
  • オーケストレーションエンジン: サービス間の連携を管理する中心的な機能。
  • メッセージフロー: すべてのリクエストはオーケストレーションエンジンを経由して処理される。

オーケストレーションエンジンは、システム全体のロジックを集約し、サービス間の通信とトランザクションの管理を行う重要な役割を果たすが、複雑さと官僚的な問題を引き起こす可能性がある。

再利用…と結合

サービスレベルでの再利用を目指すアーキテクチャは、一貫性や効率性を向上させるが、以下の課題がある。

  • 結合の増大: 変更が他サービスに波及し、リスクとコストが増加。
  • 複雑性の増加: 必要ないデータやロジックが全体に影響。
  • 開発の非効率化: 多層変更が必要で、トランザクション設計も複雑に。

再利用性は高まるものの、実運用での負担が大きい設計となる。

アーキテクチャ特性の評価

アーキテクチャ特性 星評価
分割タイプ 技術
量子数 1
デプロイ容易性
弾力性 ☆☆☆
進化性
耐障害性 ☆☆☆
モジュール性 ☆☆☆
全体的なコスト
パフォーマンス ☆☆
信頼性 ☆☆
スケーラビリティ ☆☆☆☆
シンプルさ
テスト容易性

サービス指向アーキテクチャは、分散型でありながら単一のデータベースやオーケストレーションエンジンによる結合が強く、柔軟性や性能が低い点が課題。デプロイやテストが困難で、モノリシックと分散型の欠点を併せ持つ構造となった。しかし、この失敗から分散トランザクションの難しさや技術的分割の限界が学ばれ、現代的なマイクロサービスの登場を後押しする重要な教訓となった。

マイクロサービスアーキテクチャ

マイクロサービスアーキテクチャは、近年人気を集めるアーキテクチャスタイル。

歴史

マイクロサービスアーキテクチャは、2014年にMartin FowlerとJames Lewisのブログ記事で広まり、ドメイン駆動設計(DDD)の「境界づけられたコンテキスト」に影響を受けている。このスタイルは疎結合を重視し、再利用よりも独立性と複製を優先してシステムを設計する。

トポロジー

マイクロサービスアーキテクチャでは、各サービスが単一目的に特化し、小さな独立した構成要素で構成される。各サービスは、データベースや依存コンポーネントを含め、完全に独立して動作可能。この特性により、他の分散アーキテクチャと比べてサービスの粒度が小さくなる。

分散

マイクロサービスは分散アーキテクチャで、各サービスが独立したプロセスで実行される。これによりリソース共有問題を解決し、クラウドやコンテナ技術で分離が強化される。ただし、分散によるパフォーマンス低下(ネットワーク遅延やセキュリティ処理)もあり、サービスの粒度設定が重要。

境界づけられたコンテキスト

マイクロサービスの基盤となるのは「境界づけられたコンテキスト」の考え方で、各サービスは特定のドメインやワークフローを表す。これにより、サービスは独立して動作し、結合を避け、重複を好む設計になる。サービスの粒度は慎重に決定する必要があり、小さすぎるサービスにすると通信リンクが増え、効率が下がる。境界はドメインやトランザクションに基づいて設定し、データベースも共有せず、各サービスにデータの分離を求める。これにより、サービスは最適なツールを選べる柔軟性を持つ。

API層

マイクロサービスにおけるAPI層は必須ではないが、運用基盤との連携やプロキシとしての役割を果たすために使われることが一般的。API層は、サービス間の間接化やネーミングサービスとの連携などに有益だが、メディエーターやオーケストレーションツールとして使用するべきではない。これは、マイクロサービスがドメインによって分割されているアーキテクチャであることを考慮した設計思想。

運用面での再利用

マイクロサービスでは、モニタリングやロギング、サーキットブレーカーなどの運用面での再利用をどう扱うかが重要な課題。サイドカーパターンを用いることで、共通の運用関心事(例えばモニタリングやアップグレード)が各サービスに共通のコンポーネントとして処理され、個別のチームが対応する負担を減らす。これにより、アップグレードの際、インフラチームがサイドカーを更新すれば全サービスが新機能を受け取れるようになります。

サービスメッシュは、ロギングやモニタリングを全体で統一的に制御するために、共通のサイドカーコンポーネントを接続し、サービスプレーンを通じてサービス間で一貫した運用インターフェイスを提供する。これにより、運用面での結合をグローバルに制御でき、さらにサービスディスカバリーを組み込むことで、スケーラビリティや弾力性の向上が可能となる。

フロントエンド

マイクロサービスアーキテクチャでは、ユーザーインターフェイスも分離が推奨される。主に2つのスタイルがある。

  1. モノリシックなユーザーインターフェイス: 単一のフロントエンドがAPI層を通じてバックエンドと通信。

  2. マイクロフロントエンド: 各バックエンドサービスが独自のUIコンポーネントを提供し、フロントエンドはそれを組み合わせて利用。

マイクロフロントエンドは、Reactなどのコンポーネントベースのフレームワークを使って実装できる。

通信

マイクロサービスでは、アーキテクトと開発者は、適切な粒度のデータ分離と通信を決める必要がある。サービスを分離しつつ連携させるためには、適切な通信スタイルを選ぶことが重要だ。

同期通信 vs 非同期通信
アーキテクトは、まず同期通信か非同期通信を選択する。同期通信では、呼び出し側が応答を待つ必要があり、一般的にREST APIやメッセージキューを使用してサービス間で通信する。非同期通信では、イベント駆動アーキテクチャを利用し、ブローカーパターンやメディエーターパターンが使われる。

プロトコルの選定
マイクロサービスは異種間相互運用性を活用する。サービス間で異なる技術スタックが使用されるため、プロトコルを意識した通信が求められる。

コレオグラフィとオーケストレーション

  • コレオグラフィ: 各サービスが中央のメディエーターを介さずに他サービスを呼び出す。例えば、CustomerWishlistサービスが必要な情報を他のサービスから取得する。
  • オーケストレーション: 中央のサービスが複数のサービスを調整する。例えば、ReportCustomerInformationサービスが他のサービスを呼び出す。

トランザクションとサーガ
マイクロサービス間ではトランザクション調整が難しくなる。トランザクションをサービス間で調整しない方が望ましく、サービス粒度を見直すべきだ。例外的にトランザクションが必要な場合、サーガパターンが使われる。

サーガパターン
サーガパターンでは、メディエーターが複数のサービス呼び出しを調整し、エラー時には補償トランザクションを使って失敗を巻き戻す。

アーキテクチャ特性の計測

アーキテクチャ特性 星評価
分割タイプ ドメイン
量子数 1以上
デプロイ容易性 ☆☆☆☆
弾力性 ☆☆☆☆☆
進化性 ☆☆☆☆
耐障害性 ☆☆☆☆
モジュール性 ☆☆☆☆☆
全体的なコスト
パフォーマンス ☆☆
信頼性 ☆☆☆☆
スケーラビリティ ☆☆☆☆☆
シンプルさ
テスト容易性 ☆☆☆☆

マイクロサービスアーキテクチャは、スケーラビリティ、弾力性、進化性に優れており、DevOpsや自動化の実践が重要な要素となります。しかし、分散システム特有の課題(サービス間通信の遅延や耐障害性の問題)があり、これらはサービスディスカバリーやスケーリング技術で解決可能です。パフォーマンスの問題もネットワーク呼び出しやセキュリティチェックが影響しますが、キャッシュやレプリケーションで改善できます。マイクロサービスはドメイン駆動設計に基づき、分離された小さなサービス単位で柔軟なシステムを構築します。

適切なアーキテクチャスタイルを選ぶ

アーキテクチャスタイルの選択は、組織の要件や目標に基づくトレードオフの結果だ。選ぶ際は、アーキテクチャ特性、ドメインへの適合、戦略的目標との整合性、トレードオフの分析を考慮して最適なスタイルを選ぶことが求められる。

アーキテクチャにおけるトレンドの変遷

アーキテクチャスタイルは時代とともに変化し、その選択にはさまざまな要因が影響する。以下の点がアーキテクチャにおける変遷の要素。

  1. 過去の経験:新しいアーキテクチャは過去の問題点を解決するために進化する。
  2. エコシステムの変化:ソフトウェア開発のエコシステムは絶え間ない変化を遂げ、新しいツールや技術が登場する。
  3. 新しい能力:新しい技術やツールの登場(例:コンテナ技術)がアーキテクチャに革新をもたらす。
  4. 加速する変化:技術進化のスピードが速まり、新しいツールや設計が続々と登場。
  5. ドメインの変化:ビジネスの変化や他社との合併により、開発対象となるドメインも進化する。
  6. 技術の進化:技術革新により、組織は収益に貢献する新しい技術に適応しようとする。
  7. 外部要因:コストやライセンスなど、外部要因がツールや技術選択に影響を与える。

アーキテクトは、これらの変化を理解し、業界のトレンドに従いつつ、必要に応じて例外を作る判断が求められる。

判断基準

アーキテクチャスタイルを選択する際、アーキテクトは多くの要因を考慮しなければならない。以下のポイントをしっかり考慮する必要がある。

  1. ドメイン理解:アーキテクトは、設計するドメインの主要な側面について一般的な理解を持ち、アーキテクチャの運用特性に影響する要素を把握する。

  2. アーキテクチャ特性:ドメインや外部要因をサポートするためのアーキテクチャ特性を見つけ、解明する。

  3. データアーキテクチャ:データベースやスキーマの設計に関して、DBAと協力して影響を理解する。

  4. 組織的要因:クラウドのコストや企業のM&A計画などの外部要因も考慮する。

  5. プロセス・チーム・運用要因:開発プロセスや運用との相互作用を理解し、アジャイルなどの組織特性がアーキテクチャに与える影響を考える。

  6. ドメイン/アーキテクチャの同型性:問題領域に適したアーキテクチャスタイルを選びます。例えば、カスタマイズ性が必要ならマイクロカーネルアーキテクチャが適している。

重要な決定事項は以下の通り。

  • モノリスか分散か:システムの特性に基づいて、モノリシックか分散型のアーキテクチャを選択。
  • データの配置:データをどこに置くかを決める(モノリスや分散アーキテクチャにおいて)。
  • サービス間通信:同期型か非同期型かを選択し、一般的には同期型を推奨。

最終的には、アーキテクチャトポロジーやADR(アーキテクチャデシジョンレコード)として、アーキテクトの選択や設計に対する努力が反映される。

モノリスの事例:シリコンサンドイッチ

モジュラーモノリスとマイクロカーネルの2つの実装方法を紹介し、それぞれの利点と課題について触れている。

モジュラーモノリス
モジュラーモノリスは、単一のリレーショナルデータベースを持ち、単一の量子としてデプロイされるコンポーネントベースのアーキテクチャ。この設計では、シンプルで効率的なシステム構成が求められ、ドメインごとに分割されたコンポーネントが組み合わさる。シリコンサンドイッチの場合、開発コストを抑えるためにシンプルなWebインターフェースを採用し、カスタマイズ機能が必要な場合には、ドメイン設計に合わせたカスタマイズ対応を組み込む。

マイクロカーネル
マイクロカーネルアーキテクチャでは、コアシステムが単一のリレーショナルデータベースとドメインコンポーネントで構成され、カスタマイズはプラグインとして追加される。このアーキテクチャの特徴的な点は、各プラグインが他のプラグインと結合せず、独立してデータを保持できること。また、API層にBFF(Backends For Frontends)パターンを導入することで、デバイスごとに最適化された情報を提供する点も特筆すべき。これにより、将来的な拡張性や柔軟性を持たせることができる。

両者はシンプルでありながら、異なる要素(モジュールの独立性、カスタマイズの方法、拡張性など)を提供するため、要件に応じて適切なアーキテクチャを選択することが重要。

分散型のケーススタディ:Going、Going、Gone

「Going、Going、Gone (GGG)」のアーキテクチャでは、異なる運用特性を持つ複数のコンポーネントを効率的に処理するために、マイクロサービスアーキテクチャを採用している。具体的な設計要素は以下の通り。

主要コンポーネント

  • BidCapture: 入札者のエントリーを非同期で処理。
  • BidStreamer: 高パフォーマンスな読み取り専用の入札ストリーム配信。
  • BidTracker: 2つの異なる情報ストリームから入札をリアルタイムで順序付け。
  • AuctioneerCapture: 競売人からの入札キャプチャ。
  • AuctionSession: 個々のオークションのワークフロー管理。
  • Payment: 決済処理。
  • VideoCapture: ライブオークションのビデオキャプチャ。
  • VideoStreamer: オークションのビデオストリーム配信。

設計の特徴

  • 非同期通信: サービス間で異なる運用アーキテクチャ特性に対応するため、非同期通信が多用されています。特に、決済処理のようにリクエストが限られた時間内に処理できない場合に有効。
  • メッセージキュー: 非同期通信を用いることで、信頼性やスケーラビリティを確保し、システムの脆弱性を軽減。
  • 量子分割: 量子境界を用いて、サービス、データ、通信の境界を明確に定義し、各サービスの責任を分けている。

分析
GGGアーキテクチャは、サービスごとに異なる運用特性に対応し、適切な通信スタイルを選択している。特に、非同期処理とメッセージキューを賢く使うことで、システム全体の信頼性とスケーラビリティを向上させ、将来の拡張に備えることができる設計だ。

参考

https://amzn.to/40x3Ztq

Discussion