web-dev-qa-db-ja.com

ステートフルアプリと非ステートフルアプリ

私はステートフルアプリと非ステートフルアプリについて学習してきましたが、このトピックについてはまだ少し混乱しています。

たとえば、Nodeでアプリを実行しているとします。ここで、ユーザーはsocket.ioを介して接続するとすぐにランダムな部屋に割り当てられます。これらは4つの部屋であり、永続的なものではありません。しかし、それらはハッシュ変数としてグローバル変数に格納されています。私はdb(クエリが多すぎる)やredis(高すぎる)を使用していません。

これはステートフルアプリの例ですか?

9
heyal

Webアプリケーションのコンテキストでは、データを外部(データベースなど)に保存するのではなく、一時的な状態メモリ内を維持する場合、サーバーをステートフルと呼びます。

ステートフルアプリケーションには、次のような多くの問題があります。

  • 特定のサーバーにセッションを固定せずに複数のサーバーを実行することはできません
  • サーバーを再起動すると状態が失われます

したがって、サーバー側の状態を回避することをお勧めします(ここでも、外部的にデータベースに保存されている場合を除きます)。

Webアプリバックエンドは、クライアントとサーバー間でREST原則:状態は転送されたを使用できるため、通常、セッション状態を格納する必要はありません。この状態は、 URL、Cookie、HTTP本文など。HTTPはステートレスプロトコルであるため、これが必要です(意味論的には、必ずしもその技術的根拠ではありません)。

Webソケットでは、クライアントがサーバーとの長時間のセッション/接続を維持しており、その接続には状態が含まれるため、これらの原則は少し崩れます。これは避けられませんが、Webソケットの使用がステートレスなバックエンドの設計に影響を与えるかどうか、およびその程度を制御できます。

  • どの接続がどのイベントにサブスクライブされるかを制御するインメモリデータ構造を維持することは、まったく問題ありません。

  • そのインメモリデータ構造がその情報の「真実のソース」である場合、問題があります。

    • サブスクリプションが一時的であると想定されている場合は、すべて問題ありません。
    • クライアントが再接続したときに同じサブスクリプションを再確立する場合は、この状態を別の場所に保存する必要があります。たとえば、データベースのサーバー側、またはCookieまたはLocalStorageを介したクライアント側。

一般に、次のいずれかに該当する場合は、内部サーバーの状態を維持できます。

  • 状態は外部に保存されます
  • 状態はリクエスト間で共有されません
  • 状態は、再利用可能な高価なリソースの取得にすぎません。データベース接続
  • 状態は、信頼できるデータソースのキャッシュですが、キャッシュの無効化や結果整合性などの困難な問題が発生します
17
amon

クライアントからの着信要求を処理するために必要な状態をサーバーに格納している場合、サーバーはステートフルです。別の言い方をすれば、クライアントからのリクエストを処理するために保存し、アクセスする必要がある状態です。つまり、ハッシュマップは状態なので、サーバーはステートフルです。

現在、ステートフルではないリッチな機能を実行する実際のWebアプリはほとんどありません。結局のところ、ユーザーがログインし、ログインしたクライアントの要求に応じて要求を処理する場合、定義上、ある程度、特定のクライアントに関連するサーバーに状態を保存しており、サーバーはステートフルです。 、たとえログイン情報だけでも。

そのため、サーバーの状態がゼロになることにあまり夢中にならないでしょう。重要なのは、サーバーにどのくらいの状態があるか、この状態を保存してアクセスするのに(処理、ストレージなどの観点から)どれだけ費用がかかるか、そしてこの状態でもアプリを水平にスケーリングできるかどうかです。また、サーバー上ではなく、クライアント内で実際に状態を維持します。簡単な例として、「次のページ」ボタンを持つクライアントアプリがあるとします。クライアント側の状態またはサーバー側の状態のいずれかで「次のページ」を実装できます。

クライアントの現在のページのサーバー側の状態がある場合は、「次の」ページを表示するコマンドをサーバーに送信するだけです。サーバーはそのクライアントの状態を確認し、ページを増分してから、次のページのデータを返します。

または、現在のページをクライアントに保存することもできます。クライアントが次のページを必要とする場合、クライアントは現在のページ番号を取得し、1ずつ増やし、次に表示したい特定のページ番号に対する一般的な要求を行います。

これらの実装のうち、スケールが適切だと思いますか?ユーザーが別のページを表示する2番目のタブを開いたときに実装する方が簡単ですか?水平方向にスケーリングする方が簡単です。これらすべてに対する答えは、現在のページをサーバーに保存せず、クライアントに保持し、ページNに対する一般的なリクエストをサーバーに送信するだけです。その状態をクライアント側に維持することで、個別および水平方向のスケーリングが容易になり、同じクライアントの複数のビューがサポートされます。

6
jfriend00