HTTP (HyperText Transfer Protocol) は、サーバーからクライアントにデータを転送するステートレスな要求応答モデルをサポートするために設計されました。 最初のバージョン 1.0 では、純粋に 1:1 の要求と接続の比率がサポートされていました (つまり、接続ごとに 1 つの要求と応答のペアがサポートされていました)。
バージョン 1.1 では、この比率が N:1 に拡張されました。つまり、接続あたりのリクエスト数が多くなりました。 これは、サーバーからクライアントに転送する必要がある多数のオブジェクトや要素など、Web ページの複雑さの増大に対処するために行われました。
2.0 の採用により、HTTP は接続ごとに多数のリクエスト モデルを引き続きサポートしました。 最も根本的な変更は、ヘッダーの交換と、テキストベースの転送からバイナリへの移行です。
いつの間にか、HTTP は単なるサーバーからクライアントにテキストや画像を転送する単純なメカニズムではなく、アプリケーションのプラットフォームになりました。 ブラウザの普遍性、クロスプラットフォームの性質、そして複数のオペレーティング システムや環境をサポートする大きなコストをかけずにアプリケーションを展開できる容易さは、確かに魅力的でした。 残念ながら、HTTP はアプリケーション転送プロトコルとして設計されていません。 文書を転送するために設計されました。 API などの HTTP の最新の使用法でも、ドキュメントのようなペイロードが想定されています。 その良い例は、テキストとして転送されるキーと値のペアのデータ形式である JSON です。 ドキュメントとアプリケーション プロトコルは一般にテキストベースですが、類似点はそれだけです。
従来のアプリケーションでは状態を維持するために何らかの方法が必要ですが、ドキュメントでは必要ありません。 アプリケーションは論理フローとプロセスに基づいて構築されますが、どちらの場合も、アプリケーションがユーザーの現在位置を認識する必要があり、そのためには状態が必要です。 HTTP は本質的にステートレスであるにもかかわらず、Web の事実上のアプリケーション転送プロトコルとなっています。 技術史上最も広く受け入れられ、有用なハックの一つである HTTP に、アプリケーションの使用中に状態を追跡できる手段が与えられました。 この「ハック」では、セッションと Cookie が役立ちます。
セッションは、Web サーバーとアプリケーション サーバーが状態を維持する方法です。 これらの単純なメモリ チャンクは、Web サーバーまたはアプリケーション サーバーへのすべての TCP 接続に関連付けられており、HTTP ベースのアプリケーション内の情報のメモリ内ストレージとして機能します。
ユーザーが初めてサーバーに接続すると、セッションが作成され、その接続に関連付けられます。 開発者は、そのセッションをアプリケーションに関連するデータを保存する場所として使用します。 このデータは、顧客 ID などの重要な情報から、サイトのフロント ページの表示方法などのそれほど重要ではないデータまで多岐にわたります。
セッションの有用性を示す最良の例はショッピング カートです。なぜなら、ほぼすべての人が一度はオンラインで買い物をしたことがあるからです。 ショッピング カート内のアイテムは、サーバー上のセッションで何らかの形で表現されるため、「セッション」中はそのまま残ります。 もう 1 つの良い例は、ウィザード形式の製品構成またはカスタマイズ アプリケーションです。 これらの「ミニ」アプリケーションを使用すると、一連のオプションを参照して選択できますが、最後には、追加したすべての機能の推定コストに驚くことになります。 各「オプション画面」をクリックすると、選択した他のオプションがセッションに保存され、簡単に取得、追加、または削除できるようになります。
最新のアプリケーションはステートレスになるように設計されていますが、そのアーキテクチャがその原則に準拠していない可能性があります。 現代のスケーリング方法は、多くの場合、シャーディングなどのアーキテクチャ パターンに依存しており、ユーザー名やアカウント番号などのインデックス可能なデータに基づいてリクエストをルーティングする必要があります。 これには、適切なルーティングとアプリケーションの動作を確保するために、インデックス可能なデータが各リクエストとともに運ばれるという、一種のステートフル アプローチが必要です。 この点で、現代の「ステートレス」アプリケーションと API は、多くの場合、ステートフルな先行アプリケーションと同じような注意と管理を必要とします。
問題は、セッションが接続に結び付けられ、接続が長時間アイドル状態のままになることです。 また、接続の場合の「長すぎる」の定義は、セッションに適用される場合とはかなり異なります。 たとえば、一部の Web サーバーのデフォルト構成では、接続がアイドル状態 (つまり、それ以上のリクエストが行われていない状態) になってから 15 秒後に、接続が閉じられます。 逆に、これらの Web サーバーでのセッションは、デフォルトでは 300 秒、つまり 5 分間メモリ内に残ります。 明らかに、この 2 つは互いに矛盾しています。接続がタイムアウトすると、その接続に関連付けられているセッションに何の意味があるのでしょうか。
セッションに合わせて接続タイムアウト値を増やすだけで、この差異に対処できると考えるかもしれません。 タイムアウトを増やすということは、使用されるかどうかわからない接続を維持するためにメモリを消費する可能性があることを意味します。 これにより、サーバーの同時ユーザー総数が減少し、最終的にはパフォーマンスが低下する可能性があります。 また、ほとんどの人は新しいおもちゃをいろいろと検討したりカスタマイズしたりするのに 5 分以上かかるため、接続タイムアウトに合わせてセッション タイムアウトを短縮することは絶対に望ましくありません。
重要な注意: HTTP/2 はこれらの問題の一部に対処しますが、状態の維持に関連する他の問題も導入します。 仕様では必須ではありませんが、主要なブラウザでは TLS/SSL 経由の HTTP/2 のみが許可されます。 どちらのプロトコルも、再ネゴシエーションのパフォーマンス コストを回避するために永続性を必要とし、そのためにはセッション認識、つまりステートフル動作が必要になります。
したがって、結果として、関連する接続が非アクティブのために終了した後でも、セッションがサーバー上のメモリとして残り、貴重なリソースが消費され、アプリケーションが動作しないユーザーを怒らせる可能性があります。
幸いなことに、この問題はクッキーの使用によって解決されます。
Cookie はブラウザによってクライアントに保存されるデータビットです。 クッキーには、ユーザー、ユーザーのアプリケーション、ユーザーがアクセスしたサイトに関するさまざまな興味深い情報が保存されます。 「クッキー」という用語は、UNIX コンピューティングのよく知られた概念である「マジック クッキー」に由来しており、この概念と名前の両方に影響を与えています。 Cookie は、HTTP ヘッダー Cookie を介してブラウザとサーバー間で作成され、共有されます。
クッキー: JSESSIONID=9597856473431 キャッシュ制御: キャッシュなし ホスト: 127.0.0.2:8080 接続: キープアライブ
ブラウザは、HTTP ヘッダー内の Cookie をコンピュータ上のファイルに保存する必要があることを自動的に認識し、ドメインごとに Cookie を追跡します。 特定のドメインの Cookie は常にブラウザによって HTTP ヘッダーでサーバーに渡されるため、Web アプリケーションの開発者はアプリケーションのサーバー側で Cookie を要求するだけでそれらの値を取得できます。
セッション/接続の長さの問題は、Cookie によって解決されます。 ほとんどすべての最新の Web アプリケーションは、「セッション ID」を生成し、それを Cookie として渡します。 これにより、セッションが作成された接続が閉じられた後でも、アプリケーションはサーバー上でセッションを見つけることができます。 このセッション ID の交換により、HTTP のようなステートレス プロトコルでも状態が維持されます。 しかし、Web アプリケーションの使用が単一の Web サーバーまたはアプリケーション サーバーの処理能力を超えた場合はどうなるでしょうか? 通常、ロード バランサ、または今日のアーキテクチャではアプリケーション配信コントローラ (ADC) が導入され、すべてのユーザーが可用性とパフォーマンスに満足できるようにアプリケーションが拡張されます。
最近のアプリケーションでは、Cookie が引き続き使用される場合もありますが、他の HTTP ヘッダーが重要になります。 認証と承認のための API キーは、多くの場合、HTTP ヘッダーや、バックエンド サービスのルーティングと適切なスケールに必要なデータを伝送するその他のカスタム ヘッダーを介して転送されます。 このデータを伝送するために従来の「Cookie」を使用するか、他の HTTP ヘッダーを使用するかは、全体的なアーキテクチャに対するその重要性を認識することほど重要ではありません。
これに関する問題は、負荷分散アルゴリズムは一般に、サーバー間でのリクエストの分散のみに関係していることです。 負荷分散技術は、ラウンドロビン、最小接続、最速応答時間などの業界標準アルゴリズムに基づいています。 いずれもステートフルではなく、同じユーザーがアプリケーションに対して行った各リクエストを異なるサーバーに分散させることが可能です。 これにより、1 つのサーバーのセッションに保存されたデータが「プール」内の他のサーバーと共有されることはほとんどないため、HTTP の状態を実装するために行われたすべての作業が無駄になります。
ここで、永続性の概念が役に立ちます。
永続性 (別名スティッキネス) は、単一のユーザーからのリクエストが常にそのリクエストを開始したサーバーに分散されるようにするために ADC によって実装される手法です。 一部の負荷分散製品およびサービスでは、この手法を「スティッキー セッション」と呼んでいますが、これはまったく適切な呼び名です。
永続性は、SSL/TLS 対応サイトの負荷分散で長い間使用されてきました。これは、ネゴシエーション プロセス (計算集約型) が完了してキーが交換されると、プロセスを再度開始するとパフォーマンスが大幅に低下するためです。 そのため、ADC は SSL セッションの永続性を実装し、ユーザーが常に最初に接続した同じサーバーに誘導されるようにしました。
長年にわたり、ブラウザの実装では、これらのセッションのコストのかかる再ネゴシエーションを回避する技術の開発が必要でした。 この技術は、Cookie ベースの永続性と呼ばれます。
ロード バランサは、SSL/TLS セッション ID に依存するのではなく、クライアントがサイトに初めてアクセスしたときにセッションを一意に識別する Cookie を挿入し、その後の要求でその Cookie を参照して適切なサーバーへの接続を維持します。
それ以来、Cookie ベースの永続性の概念はアプリケーション セッションに適用され、Web サーバーとアプリケーション サーバーによって生成されたセッション ID 情報を使用して、ユーザー要求が同じセッション中に常に同じサーバーに送信されるようになりました。 この機能がなければ、負荷分散を必要とするアプリケーションは、セッション情報を共有する別の方法を見つけるか、セッションと接続のタイムアウトを増やす必要があり、その結果、ユーザー ベースをサポートするために必要なサーバーの数がすぐに管理不能になってしまいます。
最も一般的な永続化形式は、HTTP ヘッダーで渡されるセッション ID を使用して実装されますが、今日の ADC は他のデータにも永続化できます。 クッキーに保存できるデータ、または IP、TCP、または HTTP ヘッダーから取得できるデータは、セッションを永続化するために使用できます。 実際、ユーザーを一意に識別するアプリケーション メッセージ内の任意のデータは、インテリジェント ADC によってブラウザーとサーバー間の接続を維持するために使用できます。
HTTP はステートレスなプロトコルかもしれませんが、私たちはユビキタスなプロトコルに状態を無理やり組み込むことに成功しました。 永続性とアプリケーション配信コントローラーを使用すると、状態を維持するために必要な Cookie とセッションのやや脆弱な統合を壊すことなく、可用性が高くパフォーマンスの高い Web アプリケーションを設計できます。
これらの機能は HTTP 状態を与えるものですが、その実装と実行はステートレスのままです。 クッキー、セッション、永続性がなければ、私たちはアプリケーションを構築するためのステートフル プロトコルを確実に見つけていたでしょう。 代わりに、アプリケーション配信コントローラーに備わっている機能がブラウザー (クライアント) とサーバーの間を仲介してこの機能を提供し、HTTP の有用性を静的 Web ページや従来のアプリケーションを超えて、最新のマイクロサービス ベースのアーキテクチャやデジタル経済の寵児である API にまで拡張します。