ステートフルとステートレスの違いは、API開発の際に重要ですが、ステートフルとステートレスのシステムを扱っているデベロッパーでなければ、この概念を十分に理解していないかもしれません。さらに言えば、スケーラブルなWebアプリの構築のために、なぜステートレスREST APIが欠かせないのかもイマイチよくわからないのではないでしょうか?本記事では、ステートフルおよびステートレスなアプリの仕組みをより深く理解するためだけでなく、これらのアイデアを最新のWeb開発のコンテキストに当てはめる際によくある疑問を詳しく説明していきます。
ステートフルアプリ と ステートレスアプリ の定義
まずは、ステートフルアプリとステートレスアプリの定義からみていきましょう:
ステートフルアプリ
ステートフルアプリは、以前のクライアント・リクエストに関する情報、ログイン/認証ステータス、または「ステート」データなどのクライアントのセッションデータを保存し、一部のステートフルシステムでは、このデータはアプリケーションを実行するサーバーに保存されます。エンタープライズアーキテクチャでは、ステートデータはキャッシュ層内に保存され、アプリケーションサーバー自体には保存されません。ステートフルアプリは、バックエンドのデータベースを持ちますが、同じクライアントからの次のリクエストを処理するときに、保存されたステートデータをコンテキストとして使用します。
従来のステートフルWebアプリでは、ユーザーがリンクをクリックしたり、送信ボタンを押したりするたびに、サーバーがWebページの再作成に関連するすべての作業を行っているため、ユーザーのステートが維持されます。この情報をサーバーまたはキャッシュ層で利用できるようにすると、サーバーがトラフィックを処理するのに十分な能力がある限り、処理が高速化されます。
ステートレスアプリ
ステートレスアプリは、クライアント・セッション(ステート)のデータを、アプリケーションが稼動するサーバー上に保存しない代わりに、バックエンドのデータベースにすべてのデータを保存するか、または、そのアプリと対話するクライアントのキャッシュにステートデータを外部化します。Webアプリでは、REST(Representational State Transfer )API を使用することで、デベロッパーは HTTP を補強してステートレスアプリにステートフルな振る舞いをさせることができるようになり、ステートレスアプリはステートフルアプリのように振る舞うことができます。例えるなら、ログインに成功すると、Webサイトのナビバーにユーザー名が表示されるようなものです。クライアントが自身のシステムに保存しているセッション識別子(通常はクッキー)のおかげで、このようなステートフルな動作が可能なのです。
ステートレスアプリは、特定のタイプのクライアント・インタラクションを遅らせることがありますが、実質的に無限のスケーラビリティを提供します。この点、REST API を使用してステートレスアプリを構築すると(リクエストごとにブラウザウィンドウに表示する内容をサーバーに再描画させるのではなく)、デベロッパーはステートフルな操作を模倣しながら、驚くほどのスケーラビリティの実現が可能になります。
ステートフル アプリを深堀り
アプリがステートフルである場合、保存されたクライアントセッションデータに依存して、新しいトランザクションを処理します。ステートフルアプリは、バックエンドのストレージにデータベースを使用しますが、アプリを実行するサーバーを使って、以前のインタラクションのデータを保存し、このクライアントセッションデータ(ステートデータ)により、アプリは以前のトランザクションのコンテキスト内で、後続のトランザクションの処理ができます。
従来のWebアプリは、リモートセッションを使用してステートを維持するステートフルなアプリであるため、すべてのセッションデータはサーバー上に保持されなければいけません。RESTを世界に紹介したロイ・T・フィールディング氏の代表的な著作には、「リモートセッションのスタイルは、サーバーコンポーネントよりもクライアントコンポーネントの複雑さを最小限に抑え、あるいは再利用を最大化しようとするクライアント ― サーバー間の変種である。各クライアントはサーバー上でセッションを開始し、サーバー上の一連のサービスを呼び出して、ついにセッションは終了する。するとアプリケーションのステートは完全にサーバー上に保持される。」とあります。
簡単な例えを挙げてみましょう。ステートフルアプリは、あなたが長年お世話になっている地元の銀行を訪れるようなものです。銀行の行員は皆、あなたのことを認識しているので、取引をする前に身分証明書を見せる必要はなく、また、あなたの過去の取引記録はその銀行で保管されています。つまり、あなたの側が「ステート」の情報を保存する必要はなく、来店して、残高についていくつか質問し、取引内容を伝えるだけでよいのです。このシステムは、銀行が一度に取引を行おうとする顧客の数を処理できる限り、迅速で効率的です。
ステートフルアプリの一例として、サーバー上にクライアント認証データを保存し、クライアントの状態を「接続」または「切断」に分類するステートフルなWebサービスがあります。また、同じクライアントからの以前のリクエストに関する情報も保存され、この情報はすべて、後続のクライアント・リクエストを処理する際のコンテキストとして使用されます。クライアントがアカウント固有の情報取得のためにクエリを送信すると、ステートフルサービスは、クライアントのIDと接続/切断の状態を判断し、このステートデータは、アプリによるリクエストの処理の仕方に影響します。
ステートフル・アプリケーションのもう一つの例は、ステートフルFTP(ファイル転送プロトコル)サーバーです。 ステートフル FTPサーバーとのやりとりは、ステートフル Webサービスと似ており、FTPサーバーはユーザーの接続状態を認識します。つまり、リクエストごとの認証が必ずしも要るわけではないということです。
結論から言うと、ステートフルアプリは、認証状態、プリファレンス、最近のアクション、ウィンドウの位置のようなUI配置などのステートデータを保存することにより、中断されたクライアントが保存された状態に戻っても、何事もなかったかのように動作することができます。ステートレスアプリが要求ごとに認証やその他の状態データを受信して処理する必要があるのとは対照的に、サーバーがクライアント要求の負荷を処理できる限り、ステートフルアプリはクライアント要求ごとに多くのデータを処理する必要がないため速いです。さらに、ステートフルアプリは、リクエストを処理する際に、データベースに多くの情報を問い合わせる必要がありません。
キーポイント:ステートフルなシステムは、他のアプリケーションと同様にデータベースを使用するが、サーバー自体で(クライアントの認証や過去のリクエストに関連する)「ステートデータ」を保持する。これにより、ステートフルなアプリは高速になり、クライアントは以前のインタラクションの履歴コンテキスト内でアプリと対話できるようになる。
ステートフルアプリのスケーリングの課題
これまでのところ、ステートフルWebアプリはすべてが優秀に思えます。リモートセッションを使うことで、過去のコンテキストや速くて効率的なクライアントとのやり取りを実現しますが、デメリットについてはまだお話していませんでしたね。ステートフルなアプリには残念な点がいくつかありますが、最も重大なのは、スケーリングの問題です。
フィールディング氏の著書に戻りましょう:「リモートセッションのメリットは、サーバーでインターフェースを集中管理しやすく、機能が拡張されたときに配備されたクライアントの不整合の懸念を軽減し、サーバー上で拡張セッションコンテキストを利用するインタラクションの効率を向上させることである。一方デメリットは、アプリケーションのステートが保存されるため、サーバーのスケーラビリティが低下する点と、モニターがサーバーのステートを完全に把握しなければならないため、インタラクションの視認性が低下することである。」とあります。
上の例で出てきた地方銀行を思い出してみてください。同じ支店に1,000人が並んで取引をしているとします。しかも支店は町に1つしかありません。一度にこれだけの数の注文を処理することはできないので、長い待ち時間が発生します。この銀行でないとあなたのことはわからないですし、ここ以外の銀行からあなたの口座記録にもアクセスできませんので、新しい銀行にも行けません。たとえ支店に顧客が殺到して取引を処理できないときでも、同じ銀行の支店に通い続けなければならないのは、スケーリングの問題なのです。あなたの街の銀行は、一度に一定数以上の取引を処理するための拡張性を備えていないのです。
このスケーリングの問題は、ステートフルアプリでも同様です。 ステートフルアプリのユーザーは、ステートデータを維持する同じシステムにリクエストを送り続けなければならず、そうしないと履歴のコンテキストが消えてしまいます。つまり、新しいクライアント・リクエストを、同じアプリを実行している他のシステムにリダイレクトすることでは、スケーリングできないのです。クライアントは再認証が必要になり、過去のトランザクションの履歴コンテキストは消えます。急速に増加するユーザーベースや予測できない量のクライアント・トラフィックに対して同じアプリ体験を提供する必要がある場合、ステートフルアプリは、サーバーが処理できないレベルまでトラフィックが増加すると、遅延やシャットダウンが発生する可能性があるのです。
一般的に、ステートレスアプリを使えばこのようなスケーリングの課題を防ぐことができます。ステートレスアプリは、自身のステートデータを保存するより「洗練された」クライアントと対話します。これにより、ステートレスアプリはステートフルな操作のように見せかけることができ、スケーリングをしやすくするために自分自身を自由に複製することができます。
キーポイント:ステートフルアプリは、クライアントとユーザーを同じサーバーにバインドすることで、それ以降のリクエストを以前のリクエストのコンテキストで処理できるようにする。トラフィックが増加した場合、ステートフルアプリを複製して新しいクライアントリクエストをリダイレクトするだけでは、ユーザーはゼロからやり直す必要があることから、ステートフルシステムは、システムが管理できる予測可能なワークロードの下で最もうまく機能する。このため、ステートフルアプリは拡張が難しく、クライアントのトラフィックが増加するとシステムが使用できなくなる傾向がある。
ステートレス アプリを深堀り
ステートレスアプリまたはステートレスプロセスは、過去のトランザクションに関連するデータをサーバーに保存せず、以前のインタラクションを知ることなく、白紙のように各トランザクションやユーザーとのインタラクションを受け入れます。コーラがほしいとボタンを押したら出てくる自販機のように、ステートレスアプリは単一の短期的なリクエストを受け取り、単一のレスポンスを提供します。
ほとんどの場合、「ステートレス」とはステートが存在しないということではなく、ただ、ステートがどこか別の場所に保持されているということです。ステートレスアプリは、ステートをサーバーに保持するのではなく、ステートを外部化すると言った方が正確です。携帯電話やパソコンのアプリ(クライアント)の多くがキャッシュを搭載しているのはこのためで、キャッシュは、ローカルシステム上にステートデータを保存し、その後のトランザクションにコンテキストを提供するのです。
ソース:https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
レオナルド・リチャードソン氏 と サム・ルビー 氏はステートレスシステムを次のようにうまく表現しています。「ステートレスとは、すべての HTTP リクエストが完全に分離して発生するということです。クライアントが HTTP リクエストを出す時、リクエストにはサーバーがそのリクエストの処理に必要なすべての情報が含まれており、サーバーは、以前のリクエストの情報に依存することはありません。もしその情報が重要であれば、クライアントは今回のリクエストでその情報を再送信しているはずです。」
スケーラブルなWebアプリケーションで使われるREST APIについて、フィールディング氏は「ステートレス制約」を「クライアントからサーバーへの各リクエストは、リクエストを理解するのに必要なすべての情報を含んでいなければならず、サーバーに保存されているコンテキストを利用することはできないため、セッションの状態は完全にクライアント上に保持される。」と説明しています。
結局のところ、ステートレスアプリは、クライアントが接続するデータベース(および場合によっては他のサービス)と対話するために使用する名前のないエージェントまたはツールのように動きます。アプリはステートレスなので、ロードバランサーは新しいインスタンスを無限に複製し、そのインスタンス間でクライアントのリクエストのバランスをとることができます。これにより、システムはどのようなレベルのトラフィックでも拡張、管理するができるのです。
ステートレスシステムの優秀な例として、Integrate.ioのAPIゲートウェイがあります。セキュリティガードと同様に、Integrate.ioはクライアントがAPIリクエストを送信するのを待ち、リクエストにはIntegrate.ioが実行するのに必要な認証/パスワードデータとコマンドがすべて含まれています。Integrate.ioはクライアントについて何もわからなくても、接続されたサービスを使ってリクエストの認証及び実行をし、負荷分散(LB)ツールは、ステートレスシステムとしてIntegrate.ioを多くの異なるサーバーインスタンスに拡張し、事実上任意の数のリクエストを処理できます。
キーポイント: ステートレスシステムでは、ステートが消えることはなく、ステートレスアプリが相互作用するクライアントやデータベースに外部化されるだけであり、この点で、ステートレスアプリには、後続のトランザクションにコンテキストを提供する独自のステート情報をキャッシュする、より洗練されたクライアントが必要である。これにより、ステートレスアプリとそのクライアントは、より独立した形でやり取りできるようになる。
ステートレス・アプリケーションのスケーリング上のメリット
ステートレスアプリは、その無限のスケーリング能力から、現代のクラウド・コンピューティングとインターネットに欠かせない存在となっています。例えばWebサイトのコンテンツを読むとき、WebブラウザはステートレスHTTPプロトコルを使ってステートレスWebサービスに接続するクライアントであり、ブラウザが送信する各リクエストは、Webサイトがクライアントの以前の動作を知ることなく、単独で動作することができます。リクエストのトラフィックが増加すると、ロードバランサは新しいサーバーにステートレスWebサービスを複製し、クライアントのリクエストをリダイレクトして、新規ユーザーと再訪問ユーザーのシームレスなエクスペリエンスを維持できます。
REST APIは、HTTPプロトコルの背後にあるステートレス原則に準拠しており、クライアントとユーザーがステートレスアプリとやり取りするための最も一般的な方法になります。REST API への各リクエストには、認証データ、GET/PUT/PATCH/DELETE コマンドなど、ステートレスアプリがリクエストを正常に処理するのに必要なすべての情報が含まれており、アプリは、GETリクエストの場合のように要求された情報を返すか、PUTリクエストの場合のようにトランザクションが成功したことを示します。他のタイプのAPIもありますが、ほとんどの場合、REST APIによってステートレス・トランザクションが可能です。
Facebookメッセンジャー は、REST API を使ったステートレス アプリの一例です。スマートフォンでメッセンジャークライアントを開くと、メッセンジャーREST API を通じて GET リクエストが送信され、最新のメッセージが取得されますが、Facebook側では、このアプリはステートレスであり、スマートフォンへの応答の送信に、以前のトランザクションに関する知識は必要ありません。過去のデータをキャッシュに保存し、あなたの端末に過去のコンテキストを提供するのは、Facebook側でなくあなたの端末のクライアントです。繰り返しになりますが、Facebookメッセンジャーサービスがクライアントからのリクエストで過負荷になった場合、ロードバランサがリクエストを重複したインスタンスに分散させることでトラフィックの管理ができます。
フィールディング氏は、REST制約を守ることのメリットを3つ挙げています:「【1】監視システムがリクエストの全容把握に単一のリクエストデータ以外を見る必要がないため、可視性が向上する。【2】 部分的な不具合からの復旧が容易になるため、信頼性が向上する。【3】リクエスト間でのステートの保存が必要ないため、サーバーコンポーネントがリソースをさっと解放することができ、さらにサーバーがリクエスト間のリソース使用を管理する必要がないため、実装が簡素化されるためスケーラビリティが向上する。」
キーポイント:ステートレスアプリは、最新のクラウド・コンピューティングとWebサービスに不可欠であり、大抵のステートレスアプリはREST APIを公開しているため、他のクライアントやサービスはそれらとのやり取りが可能。最も人気のあるWebサイト、Webサービス、SNSプラットフォーム、インターネットベースのアプリケーションの多くはステートレスである。
ステートレスアプリ、マイクロサービス、コンテナ
この部分を終わる前に、ステートレスアプリをマイクロサービスやマイクロサービス・ベースのアプリケーション・アーキテクチャという最新のコンテキストに置くことが重要です。マイクロサービスはステートフルになり得ますが、通常は単一のサービスを実行することに焦点を当てた、シンプルなステートレスアプリであり、ステートレスマイクロサービスは、他のアプリやクライアントがそれらと対話できるようにするREST APIを公開します。
マイクロサービスをコンテナ化すると、複数のマイクロサービスを他のマイクロサービスと同じサーバーカーネル上で分離して実行することができます(これにより、リソースとサーバーライセンス料を節約することができます)。コンテナ化されたマイクロサービスには、コード、ライブラリ、その他独立して実行するのに必要なものすべてが単一のパッケージにまとめられており、それ以上のものはありません。Bizetyは、「通常のオペレーティングシステム上で動作するコンピュータと比べて、コンテナ内で動作するプログラムは、コンテナの中身とその特定のコンテナに割り当てられたデバイスしか見ることができない。」と述べています。
最終的には、デベロッパーはマイクロサービスのネットワークを緩やかに繋げ、モジュラーまたは「プラグ可能」なマイクロサービスベースのアプリケーション・アーキテクチャを形成することができます。マーティン・ファウラー氏は、このことを「マイクロサービス・アーキテクチャ・スタイルは、単一のアプリケーションを小さなサービスのスイートとして開発するアプローチであり、それぞれが独自のプロセスで動作し、軽量なメカニズム(多くの場合はHTTPリソースAPI)で通信する。これらのサービスは、ビジネス機能を中心に構築され、全自動デプロイメント機械で独立してデプロイ可能である。」と説明しています。
この場合の「全自動デプロイ機械」とは、Kubernetesのような技術のことを指します。Kubernetesは、マイクロサービスベースのアーキテクチャの管理のために、自動負荷分散などを実行するコンテナオーケストレーションツールです。基本的に、コンテナ化されたマイクロサービスの自動的複製、クライアントトラフィックの分散、サーバーリソースの調整、最適なパフォーマンスの実現をし、これらすべてによって、さまざまなレベルのクライアント・トラフィックに対処するためにアプリケーションを拡張することができます。それによりKubernetesは、何千ものコンテナ化されたマイクロサービスをスピンアップして、事実上あらゆる数のリクエストの管理ができます。
キーポイント: コンテナ化されたマイクロサービスがステートレスである場合、コンテナ・オーケストレーションとロードバランシングツールがクライアントのトラフィックに応じて個々のアプリケーションコンポーネントの新しいインスタンスを自動的にスピンアップするため、スケーラビリティと高可用性がサポートされる。これにより、あらゆるレベルのトラフィックを処理するためにスケールアップまたはスケールダウンするアジャイルフレームワークが実現される。
ステートフルアプリとステートレスアプリに関するまとめ
ステートフルアプリとステートレスアプリの使い分けは、つまりスケーラビリティ要件とアプリで何を行う必要があるかということです。アプリがトランザクションをコンテキスト内で処理するためにセッションデータを保存する必要があり、サーバーが予想される処理負荷を処理できる場合は、おそらくステートフルシステムが最適です。一方、REST APIトランザクションを処理し、クライアントのリクエストに応答して情報を提供する必要があり、トラフィック レベルが指数関数的に増大するようなアプリを構築する場合は、ステートレス アプリを使用することになるでしょう。
Integrate.io:アプリとサービスをつなぐREST APIをあっという間に自動生成
ステートフルおよびステートレスアプリは、ほとんどはクライアントやユーザーがサービスを利用できるようにするためにREST APIが提供されます。特に、プラグ可能でステートレスなマイクロサービスからなる、スケーラブルでサービス指向のアプリケーション・アーキテクチャを構築する場合、REST API 開発はアプリケーション開発と密接に関係します。ただ、単一のREST APIを手作業でコーディングすると、アプリケーション開発のタイムラインに数週間以上の時間がかかることがあります。
そこで、Integrate.ioのAPIゲートウェイの出番です。Integrate.io自体はスケーラブルでステートレスなアプリであり、アプリの構築やAPIリクエストの管理、アプリ間のインタラクションのための最先端のツールを提供します。あらゆるデータベースのための完全に文書化されたREST APIを数分で生成できるREST API自動生成ツールが、Integrate.ioの最も人気のある機能の1つとしてあります。
データ統合プラットフォームであるIntegrate.io内では、企業はクラウド上でデータの統合、処理、分析のための準備を行うことができます。コードや専門用語を有しなくても使用できる環境であるため、ハードウェア、ソフトウェア、または関連インフラに投資することなく、どのような組織・個人でもビッグデータがもたらす機会をご享受頂けます。
14日間無料トライアル、無料デモやご相談は、こちらのリンクより初回ヒヤリングをご予約頂けますと幸いです。後ほど、弊社担当者よりご連絡させて頂きます。