2007-10-28

ステートレスとは何か

RestWiki をたまに見直すと新たな発見があって面白い。

たとえば先日、「ステートレスなやりとりとは何か(What is Stateless Interaction?)」という箇所を見つけて、興味深く読んだ。このページは以前も絶対に読んでいるはずなのだが、 人間は忘れてしまうものである。

RestWiki の例でも充分わかりやすいのだけれど、自分でも例を思いついたので書きとめておく。

ステートフルサーバとステートレスサーバはどう違うのか。

まずは、ステートフルの例:

  • 客: こんにちは
  • 店員: いらっしゃいませ。○○バーガーへようこそ
  • 客: ハンバーガーセットをお願いします
  • 店員: サイドメニューは何になさいますか?
  • 客: ポテトで
  • 店員: ドリンクは何になさいますか?
  • 客: ジンジャーエールで
  • 店員: +50円でドリンクをLサイズにできますがいかがですか?
  • 客: Mでいいです
  • 店員: 以上でよろしいですか?
  • 客: はい
  • 店員: かしこまりました

これはいたって普通の会話に見える。では、ステートレスな場合はどうなのか。

  • 客: こんにちは
  • 店員: いらっしゃいませ。○○バーガーへようこそ
  • 客: ハンバーガーセットをお願いします
  • 店員: サイドメニューは何になさいますか?
  • 客: ハンバーガーセットをポテトでお願いします
  • 店員: ドリンクは何になさいますか?
  • 客: ハンバーガーセットをポテトとジンジャーエールでお願いします
  • 店員: +50円でドリンクをLサイズにできますがいかがですか?
  • 客: ハンバーガーセットをポテトとジンジャーエール(M)でお願いします
  • 店員: 以上でよろしいですか?
  • 客: ハンバーガーセットをポテトとジンジャーエール(M)でお願いします。以上
  • 店員: かしこまりました

これは明らかに冗長であほらしいのだけれど、サーバがステートレスというのはこういうことである。

ステートフルの例では、2回目以降の対話では、客(クライアント)はそれまでの前提(ハンバーガーセットを頼んでいること)は 繰り返さなくてもよかった。なぜか。それは店員(サーバ)が客(クライアント)の注文状態を覚えていたからである。 この店員(サーバ)は「この客(クライアント)はハンバーガーセットをポテトで頼んでいる」ということを覚えている。 これをアプリケーション状態、あるいはセッション状態と呼ぶ。 次にドリンクの種類を聞いたときに店員(サーバ)は自分で覚えている客(クライアント)のアプリケーション状態を 「この客はハンバーガーセットをポテトとジンジャーエールで頼んでいる」と更新する。

ファーストフード店の店員であれば、ステートフルな実装は当たり前なのだが、Web サーバは異なる。 それはスケーラビリティの問題である。 店員(サーバ)が一人の客(クライアント)をずっと相手にしていると、その間別の客に対応することができない。 店が込んできたら(アクセスが集中したら)、店員を増員して(Webサーバを増設して)対応する。 普通の店舗では、ひとつのレジで一人の店員がずっと同じ客を受け付けるのだが、 Web の場合は複数の Web サーバ(比較的少数)で複数のクライアント(比較的多数)を同時に受け付ける。 ここで、ステートレスサーバであれば、以下のように、各インタラクションで別々の店員(サーバ)が 客(クライアント)の注文(リクエスト)に応答(レスポンス)することが可能になる。

  • 客: こんにちは
  • 店員1: いらっしゃいませ。○○バーガーへようこそ
  • 客: ハンバーガーセットをお願いします
  • 店員2: サイドメニューは何になさいますか?
  • 客: ハンバーガーセットをポテトでお願いします
  • 店員3: ドリンクは何になさいますか?
  • 客: ハンバーガーセットをポテトとジンジャーエールでお願いします
  • 店員4: +50円でドリンクをLサイズにできますがいかがですか?
  • 客: ハンバーガーセットをポテトとジンジャーエール(M)でお願いします
  • 店員5: 以上でよろしいですか?
  • 客: ハンバーガーセットをポテトとジンジャーエール(M)でお願いします。以上
  • 店員6: かしこまりました

ステートレスサーバというのは一見冗長なように見えるが、 スケーラビリティの観点から見ると、理に適っているものである。

合わせて読みたい: A Web-Centric Approach to State Transition

4 件のコメント:

  1. にっくと申します。通りがかりのコメント失礼いたします。

    RESTのステートレスの議論で疑問に思うのは、「ステートフル/ステートレス」という設計議論はRESTと直交する考えではないか? という点です。

    たとえば、

    ・ショッピングカート内容をDBサーバに保存する
    ・ユーザ登録情報をDBサーバに保存する

    こうしたWebサイトは、アプリサーバはステートレスになりますが、クライアントからは「ステートフルなサーバ」として見えますので、以前に送信したリクエストを再送する必要はありません。

    RESTfulなサイトにするには、カート内容をDBサーバに保存せず、毎回URI上で指示すべきなのでしょうか? そんなことしなくても、RESTの恩恵は十分に受けられると私は思うのですが、いかがでしょうか。

    返信削除
  2. RESTful を「Roy Fielding の論文に載っているアーキテクチャ制約をなるべく満たしている」と定義するなら、ステートレスではないからといって即刻 RESTful でなくなることはないですね。ステートフルだけど、統一インターフェース、階層化システムを利用して、いる RESTful なシステムも考えられます。

    > ・ショッピングカート内容をDBサーバに保存する

    ショッピングカートリソースを作り、そのリソースにURIを与え、そこに商品を追加し、ステートレスにそのカートにアクセスできるのなら RESTful だと思います。

    > ・ユーザ登録情報をDBサーバに保存する

    ユーザリソースをつくり、そのリソースに URI を与え、ステートレスにそのカートにアクセスできるのなら RESTful だと思います。

    > RESTfulなサイトにするには、カート内容をDBサーバに保存せず、毎回URI上で指示すべきなのでしょうか?

    これは設計の問題です。このエントリの例はステートレスとステートフルの違いを単純化して強調していますが、RESTful にショッピングカートを設計する方法はたくさんあります。

    ・すべてのリクエストに商品情報をすべて含めるパターン
    ・ショッピングカートリソースを作るパターン
    ・Ajax 的にクライアント側でカート情報を保持するパターン

    などがあると思います。

    返信削除
  3. なるほど、ステートフルだけどRESTfulなシステムというのもありえるのですね。お返事ありがとうございました。

    返信削除
  4. 突然失礼いたします。
    zouともうします。

    大変わかりやすい例えで、
    すんなり理解ができました♪

    ありがとうございます。

    返信削除