高可用性アプリケーションの作成に最も活用される設計パターンは何ですか? [閉まっている]

StackOverflow https://stackoverflow.com/questions/814742

質問

同様に、回避すべき設計パターンはありますか?

役に立ちましたか?

解決

サーバータイプのアプリケーションを作成していると仮定します(しばらくの間Webアプリを終了します-役立つ市販のソリューションがいくつかありますので、この素晴らしい新しいタイプのサーバーは書き込みを行っています"ですが、HAの問題にしたいです。

サーバー実装では、クライアントからの要求は通常(何らかの形式で)イベントまたはコマンドタイプパターンに変換され、1つ以上のキューで実行されます。

そのため、最初の問題-クラスター内で生き残る方法でイベント/コマンドを保存する必要があります(つまり、新しいノードがマスターとして引き継ぐと、実行する必要がある次のコマンドを見て開始します)。

シングルスレッドサーバーimplで開始します(最も簡単な概念はマルチスレッドにも適用されますが、独自のissue0があります。コマンドを処理する場合、何らかのトランザクション処理が必要です。

もう1つの懸念事項は、副作用の管理と、現在のコマンドの失敗をどのように処理するかです。可能であれば、トランザクションの方法で副作用を処理し、すべてまたはゼロになるようにします。すなわち。コマンドが状態変数を変更するが、実行の途中でクラッシュし、「前」に戻ることができる場合状態は素晴らしいです。これにより、新しいマスターノードはクラッシュしたコマンドを再開し、コマンドを再実行することができます。良い方法は、副作用を小さなタスクに分割して、任意のノードで再び実行できるようにすることです。すなわち。メインリクエストの開始および終了タスクを保存します。多くの小さなタスクは、タスクごとに1つの副作用のみを処理します。

これは、設計に影響する他の問題ももたらします。これらの状態変数は、必ずしもデータベースの更新ではありません。それらは、クラスター内で分散する必要がある共有状態(内部コンポーネントの有限状態マシンなど)である可能性もあります。そのため、マスターコードが必要な状態の一貫したバージョンを確認する必要があるように変更を管理し、クラスター全体でその状態をコミットするためのパターン。何らかの形の不変の(少なくとも更新を行うマスタースレッドからの)データストレージを使用すると便利です。すなわち。すべての更新は、クラスター全体(またはデータの一貫性のためにクラスター全体の最小メンバー数)を更新した後、更新でローカルのメモリコピーのみを更新する何らかのメディエーターまたはファサードを通過する必要がある新しいコピーで効果的に行われます。

これらの問題の一部は、マスターワーカーシステムにも存在します。

また、状態の更新で問題が発生する可能性のあるものが増えるにつれて、適切なエラー管理が必要になります(現在ネットワークが関与しているため)。

状態パターンを頻繁に使用します。 1行の更新ではなく、副作用のためにリクエスト/レスポンスを送信し、会話固有のfsmを使用して進行状況を追跡します。

別の問題は、エンドポイントの表現です。すなわち。マスターノードに接続されたクライアントは、新しいマスターに再接続して、結果をリッスンできる必要がありますか?または、保留中の結果をすべてキャンセルし、クライアントに再送信させるだけですか?保留中のリクエストの処理を許可する場合、エンドポイント(クライアント)を識別する良い方法が必要です(つまり、ルックアップで何らかのクライアントID)。

クリーンアップコードなども必要です(つまり、クライアントが再接続して永遠に待機するのを待つ必要はありません)。

多くのキューが使用されます。そのため、多くの人はトランザクションバスでイベントをプッシュするために、何らかのメッセージバス(Javaではjmsと言います)を使用します。

Terracotta(Javaの場合も同様)は、この問題の多くを解決します-メモリを更新するだけです-テラコッタはここであなたのファサード/メディエーターです。彼らはあなたのためにアスペクトを注入しました。

Terracotta(私は彼らのために働きません)-「スーパースタティック」の概念を導入するため、これらのクラスター全体のクールなシングルトンを取得しますが、これがテストおよび開発ワークフローにどのように影響するかを意識する必要があります-すなわち。 inheriの代わりに多くの構成を使用する

他のヒント

信頼できるソフトウェアを作成する1つのアプローチは、クラッシュ専用ソフトウェア

です。
  

クラッシュ専用ソフトウェアは、安全にクラッシュし、迅速に回復するソフトウェアです。停止する唯一の方法はクラッシュすることであり、起動する唯一の方法は回復することです。クラッシュのみのシステムは、リトライ可能なリクエストと通信するクラッシュのみのコンポーネントで構成されています。障害は、障害のあるコンポーネントをクラッシュして再起動し、タイムアウトになったリクエストを再試行することで処理されます。多くの場合、クラッシュリカバリは後からではなく開発プロセスの最重要市民であり、明示的なシャットダウンに余分なコード(および関連するインターフェイスとバグ)は必要ないため、結果のシステムはより堅牢で信頼性が高くなります。すべてのソフトウェアは安全にクラッシュして迅速に回復できるはずですが、クラッシュのみのソフトウェアはこれらの品質を備えている必要があります。そうしないと、その不足がすぐに明らかになります。

リリースすることをお勧めしますナイガード。彼は、実動システムに影響を与えるいくつかのアンチパターンと、1つの誤ったコンポーネントがシステム全体をダウンさせないようにするパターンを概説しています。本は3つの主要な領域をカバーしています。安定性、容量、および一般的な設計(ネットワーク、セキュリティ、可用性、および管理をカバー)。

以前の職場は、Nygardが概説するほぼすべての単一の失敗シナリオ(結果として生じる停止ごとに収益の損失を伴う)に噛まれました(一度または別のところで)。彼が提案する手法とパターンのいくつかを実装すると、システムが大幅に安定し、予測可能になりました(そして、はい、この本は少しJava中心ですが、原則は多くのコンテキストに適用できます)。

間違った:

  

...そしてストレージサーバーがあります

良い:

  

...(複数の)ストレージのファームがあります   (複数の)ロードバランサーが前面にあるサーバー   それらの

  • すべての前にロードバランサーを配置します。現時点では4つのバックエンドを使用できますが、将来は400のバックエンドを使用できるようになるため、バックエンドを使用するすべてのアプリではなく、LBでのみ管理するのが賢明です。

  • 複数レベルのキャッシュを使用します。

  • thigsの高速化に関する一般的なソリューション(memcachedなど)を探します。

  • システムを更新する場合は、複数の小さなステップで部分的に実行します。 1つの大きなステップ(古いステップをオフにして、新しいステップをオンにして、それが機能することを祈る)でそれを行うと、ほとんどの場合失敗します。

  • ものにDNS名を使用する、例えば storage-lb.servicename は、すべてのストレージロードバランサーのアドレスに解決されます。追加したい場合は、dnsを変更するだけで、すべてのサービスが自動的に使用を開始します。

  • シンプルに保ちます。依存するシステムが多いほど、サービスが被害を受けます。

高可用性(HA)システムの設計は、活発な研究開発分野です。 ACMまたはIEEEを見ると、サービスの品質(可用性、信頼性、スケーラビリティなど)とそれらの達成方法(疎結合、適応など)に関する多数の研究論文があります。より実用的なアプリケーションを探している場合は、クラスタリング、グリッド、またはクラウドのような機能を可能にするために構築されたフォールトトレラントシステムとミドルウェアをご覧ください。

レプリケーションとロードバランシング(別名、リバースプロキシ)は、HAシステムを実現する最も一般的なパターンの一部であり、あまりにも緊密に結合されていないことを前提として、基盤となるソフトウェアにコードを変更せずに実行できることがよくあります。最近のクラウド製品の多くは、本質的にレプリケーションと負荷分散によって実現されていますが、幅広いシステム需要を処理するために弾力性を構築する傾向があります。

ソフトウェアコンポーネントとともに状態をレプリケートする必要がないため、ソフトウェアコンポーネントをステートレスにすると、複製の負担が軽減されます。ステートレスは、HTTPが非常にうまくスケーリングする主な理由の1つですが、多くの場合、アプリケーションは独自の状態(セッションなど)を追加する必要があり、それを複製する必要があります。

したがって、密結合システムよりも疎結合システムの可用性を高める方が簡単です。システムのコンポーネントの信頼性がシステム全体の信頼性を決定するため、信頼性の低いコンポーネントを交換する必要がある場合があります(ハードウェア障害、ソフトウェアバグなど)。実行時に動的な適応を可能にすると、システム全体の可用性に影響を与えることなく、これらの故障したコンポーネントを交換できます。疎結合は、送信者と受信者が同時に利用可能である必要はないが、システム自体はまだ利用可能であるという信頼できるメッセージングシステムを使用するもう1つの理由です。

私が理解しているように、HAアーキテクチャのJavaアプリケーション部分で使用する特定のパターンを探しています。もちろん、使用できるパターンとベストプラクティスは多数ありますが、これらは実際には「HAパターン」ではありません。むしろ、それらは多くのコンテキストで利用できる良いアイデアです。

私が言いたいのはこれだと思います。高可用性アーキテクチャは、多数の小さなパーツで構成されています。これらの小さな部品の1つを選択して調べると、おそらくこの小さなコンポーネントには魔法のようなHA属性がないことがわかります。他のすべてのコンポーネントを調べると、同じことがわかります。 HAアプリケーションになるために、それらがインテリジェントな方法で結合されるときです。

HAアプリケーションは、最初から最悪の事態を計画するアプリケーションです。 「このコンポーネントは非常に安定しているため、追加の冗長性は必要ありません」という点で考えたことがありますおそらくHAアーキテクチャではありません。結局のところ、あなたが予見する問題のシナリオを処理するのは簡単です。システムをダウンさせるのはあなたを驚かせるものです。

これにもかかわらず、HAコンテキストで特に役立つパターンがあります。それらの多くは、Martin Fowlerによる古典的な本" Patterns of Enterprise Application Architecture" に文書化されています。

" 高可用性 "を解釈しています。 " ゼロダウンタイム " `として、他のSEの質問に従って実装できます:

Javaアプリのゼロダウンタイム展開

  1. A / Bスイッチ:(ローリングアップグレード+フォールバックメカニズム)
  2. 並列展開– Apache Tomcat:(Webアプリケーションのみ)
  3. 遅延ポートバインディング
  4. 高度なポートバインディング

これらの概念のいくつかを使用して、上記のアプローチを補完するソフトウェアの観点から高可用性システムの設計パターンを考え出します。

使用するパターン:

プロキシ / 工場

プロキシオブジェクトがあれば、プロキシがリクエストのリダイレクト先を決定します。バージョン1&があると仮定します。ソフトウェアのバージョン2。クライアントが古いプロトコルで接続している場合は、バージョン1ソフトウェアにリダイレクトします。新しいクライアントは、バージョン2に直接接続できます。プロキシには、FactoryメソッドまたはAbstractFactoryのいずれかを使用して、ソフトウェアの新しいバージョンをレンダリングできます。

戦略

アルゴリズムのファミリから1つのアルゴリズムを選択することにより、実行時にアルゴリズムを変更できます。航空会社を例にとると、ピーク時以外のピーク時とピーク時のトラフィックの月にDiscountFareとNormalFareアルゴリズムを切り替えることができます。

デコレーター

実行時にオブジェクトの動作を変更できます。新しいクラスを追加し、追加の責任を飾ります。

アダプター

バージョン1とバージョン2の間でインターフェースまたは契約を変更する場合に役立ちます。アダプターは古い&の両方に応答します。新しいクライアントが適切にリクエストします。

一般的なガイドライン:

  1. オブジェクト間の疎結合
  2. アプリケーションの S.O.L.I.D の原則に従う

上記のパターンについての理解を深めるには、 sourcemaking Webサイトの記事を参照してください。

使用しないもの:

設計パターンとは別に、アプリケーションのダウンタイムをゼロにするためにいくつかの予防措置を講じる必要があります。

  1. システムに単一障害点を導入しないでください。
  2. 分散キャッシュ(Terracottaなど)/ locksを控えめに使用します。
  3. サービス間のハードカップリングを削除します。メッセージングバス/フレームワーク(JMS、ActiveMQなど)を使用して、サービス間の密結合を削除します

高可用性とは、コーディング規約よりもハードウェアの可用性と冗長性のことです。ほとんどすべてのHAケースで使用するパターンがいくつかあります。データベースオブジェクトにシングルトンパターンを選択し、ファクトリパターンを使用してシングルトンを作成します。ファクトリは、データベースの可用性の問題(ほとんどの可用性の問題が発生する場所)を処理するロジックを持つことができます。たとえば、マスターがダウンしている場合、マスターが戻るまで読み取りと書き込みの両方のために2番目のマスターに接続します。これらが最も活用されているパターンかどうかはわかりませんが、私のコードで最も活用されています。

もちろん、このロジックは__constructメソッドで処理できますが、ファクトリパターンを使用すると、コードとデータベース接続の問題を処理する方法の意思決定ロジックをより適切に制御できます。ファクトリを使用すると、シングルトンパターンをより適切に処理できます。

装飾パターン観測パターンは絶対に避けます。どちらもコードの複雑さを引き起こし、保守が困難になります。これらはあなたのニーズに最適な選択肢ですが、ほとんどの場合そうではありません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top