Play Framework 2.3 For Java ことはじめ #12 sessionとcache編

f:id:masato47744:20140720125846p:plainPlay Framework 2.3 For Java 入門記事一覧

第12回はPlay frameworkのsessionCacheついて説明します。

Javaアプリケーションの世界で俗に言われているsessionとPlay frameworkのsessionは微妙に違います。という辺りから説明してみようと思います。

そもそもHTTPのsessionって何

ざっくり言うと、サーバー側で接続してくるユーザーを覚えておく仕組み。サーバーがセッションIDを発行してユーザーに関する情報をサーバー側に保存しておくことができます。

http sessionとかでググるとたくさんでてきます。このあたりが簡潔で分かりやすいです。

Play frameworkのsessionの使い方

Play frameworkでは、sessionという仕組みがあって、そのオブジェクトを経由すれば簡単にセッションに値を保存したり取得したりすることができます。使い方は、簡単でJavaSessionFlashに書いてある通り、controllerの処理の中で、こんな風に使います。

// sessionに値をセット
session("connected", "user@gmail.com");
// sessionにセットした値を取得
String user = session("connected");
// sessionの値をクリア
session().remove("connected");

好きなキー名を指定して、文字列を保存することができます。

ただ、sessionって書いてあるから、一見サーバー側に保存されてるように思うかもしれませんが、実は、Play frameworkではcookie、つまり、サーバー側ではなくブラウザ側にデータが保存されています。
実際にsessionに値をコントローラーでセットしたあとのページを、ChromeのDeveloper ToolsでCookiesのところを見てみればどうなってるか分かるでしょう。

ここが一般的なJavaのアプリケーションとは微妙に違うところです。

Play Frameworkのsessionのメリットとデメリット

ここで、なぜPlay Frameworkではサーバー側にデータを保存しないのか?という疑問がわきますが、これにはこれでメリットがあります。

例として、サーバーの負荷を分散するために、サーバーを複数台用意してそれぞれに処理を振り分けるということをしようと考えたとしましょう。このときに、セッションをサーバー側に値を保存するという方法では、ある問題が発生します。
分散させたサーバーA、Bが稼働していたとして、次のケースでサーバーはユーザーを認識できなくなります。

  • ユーザーは、サーバーAに接続してきてサーバーAはユーザーのセッションデータを保存
  • 次にユーザーがサーバーBに接続
  • セッションデータはサーバーAにあるため、サーバーBはユーザーを識別することができない

このように、処理を行うサーバーを複数台用意したときに、ユーザーは常に同じサーバーに接続しなければならないという保証が必要になります。でも、Play Frameworkのsessionは、ブラウザ側にデータを保存しているので、どのサーバーに接続してもOKということになり、何も気にすることなくサーバーを増やすことができます。

こちらの方の記事ステートレスなPlay2でログイン状態を管理する - C Sharpens you upの銀行のたとえが分かりやすいです!

一方で、このcookieに保存するということにも、デメリットはあって、cookieにはサイズ制限があるので、4KBぐらいの文字列しか保存できません。
最新ブラウザのクッキーの制限(数,サイズ)を調べてみた - ITコンサルタント成長録

あとは、ブラウザ側にデータが保存されているので、一度発行してしまったものを自分のアプリケーションに接続させることなく強制的に削除したいと思っても、その仕組みは作ることができません。

Play FrameworkのCache

その辺りの、メリットデメリットをふまえた上で、Play Frameworkには、Cacheという仕組みがあります。これは、サーバー側で値を保持する仕組みなので、一般的なJavaのアプリケーションのセッションに近いものがあります。

Playの公式ページJavaCacheに使用方法は書いてあります。

値の操作方法はこんな感じでほぼsessionと似たようなものですが、文字列以外も保存できたり、有効期限を設定できたりします。

// キャッシュをセット(文字列じゃないオブジェクトをセットできる)
Cache.set("item.key", frontPageNews);
// 15分間だけ有効期限をつけてキャッシュをセット
Cache.set("item.key", frontPageNews, 60 * 15);
// キャッシュを取得
News news = (News) Cache.get("item.key");
// キャッシュを削除
Cache.remove("item.key");

Cacheを使うということは、サーバー側に保存することになるので、サーバーをたくさん増やすことができなくなってしまうじゃないかと思うかもしれません。

ですが、そこはちゃんとPlay Frameworkでは考えてあって、Cacheに保存したデータを別のサーバーで管理できる仕組みが用意されています。なので、Playが動いているアプリケーションサーバー自体を増やしても、各サーバーはCacheが保存されているサーバーを見に行けばいいので、問題を解決しています。

まとめ

すごい雑ですが、Play FrameworkのsessionCacheについてまとめました。 sessionCacheの違いを理解しながら、保存するデータの性質を見極めてどっちを使うかを決めて欲しいです。 Play Frameworkは、他のフレームワークと違ってステートレスで、スケーラブルなと言われていた理由が少し分かった気がしました。