ようやく人並みの生活が送れそうになってきた程度の体調と言うか、なんというかしばらく運のなかったしょっさんです、おはようございます。
3週間くらい、朝いつもの時間に起きることができなかったので、1月の後半は何もできずにストレスだけのたまっていく日々でした。あれはツライ。
実態としては「胃腸炎」→治った→「韓国出張」→「胃腸炎」→寝込む→治った!!→「腰痛」というフルコンボで、まだ腰の痛みは残っていてちょっとしんどいです。それでいてさらに畳み込むような精神攻撃があったので、しばらく凹んでましたが、美味しいもの食って治りました。単純って素晴らしい。
ステートレスアプリケーションの定義
最近、RESTfulなWeb APIサーバのコードを書いてます(某原稿のために)。セッション・ステートをどうしようかってところで、今回はJWT(JSON Web Token)を採用しました。原稿の連載の前回で「サーバでセッションを保持するがために、サーバで障害が発生したときにセッションが全てなくなっておじゃんになるので、これをどうしましょうか」という問いに対する答えとしてJWTという答えを今回導き出しました。某SalesforceでもJWTを使ったセッション連携が利用できたりもするので、一応、使う程度には知見があったというのも背景にあります。
が、これでいいんだっけという考えが出てくるわけです(お金をもらって情報を提供する側として)。
Webアプリケーションの原則として、The Twelve-Factor Appの原則を是としている身からしてみると、一度立ち戻ってみるのも良いかと思い読み直してみました。VI.プロセス に書いてあります。リンク先は日本語なのに、なぜか英文を引用してみますが、重要なポイントは2つあります。
Twelve-factor processes are stateless and share-nothing. Any data that needs to persist must be stored in a stateful backing service, typically a database.
「ステートレス」かつ「シェアードナッシング」であること。すべての永続化が必要なデータは、バックエンドのステートフルなサービスに保存「しろ」。must なんで最上級命令と受け取って良いでしょう。アプリケーションの実行されるランタイム環境では、プロセルの利用する「メモリ」「ファイルシステム」は一時的なキャッシュとしての利用は認められても、それ以外で利用することはほぼ禁止されています。これは、プロセスには「コードのデプロイ」「設定変更」「プロセスの物理的な移動(要は障害のこと)」などの再起動要因があり、サービスの継続性を考慮しているからです。
では、ステートレス・シェアードナッシングなアプリケーションって、何を行えばよいの?については、次の文が答えになります。
Session state data is a good candidate for a datastore that offers time-expiration, such as Memcached or Redis.
「期限付き」のデータストアにセッション情報を保持しよう。例えば、MemcachedやRedisなどとあります。重要なことは「セッション情報はプロセス以外のデータストアに保存する」ことと「期限付き」であることを定めています。なので、セッション情報をサーバ側で持つなと言っているわけではなく、必要なセッション・ステート情報は、決められた期限内だけ、プロセス外の安全なデータストア(プロセスとは影響なくデータの欠落のない)へ保存すればよいわけです。
あくまでもアプリケーションプロセスでは、セッション・ステートの情報を持つなと言っているだけで、その情報はどこかで持たなければならないということです。じゃぁそれをどこで持つんだといえば、サーバ側であれば「期限付き」データストアであることとなります。が、そのデータストアが安全に動作することも前提となっています。プロセスとしてはステートレスにデザインできたけれども、データストアがちょいちょい落ちてしまうんであれば、その最中はサービスが停止してしまいます。潤沢にお金をかけられて、セッション情報をコントロールしたければ、高可用性のデータストアを準備して対処するのは良い方法でしょう。
がしかし、潤沢な予算がない場合や影響を局所化するなどの目的でいけば、クライアント側にステートをもたせておいて、それを毎度毎度サーバに送ってもらう方式にすれば良いです。サーバ側では何も一切面倒を見ずに、常にクライアントから送られてくる認可情報をベースにアクセス制御を行えばよいだけですし。クライアントで障害があった場合には、継続性がなくなりますが、利用者のうちの一人です。セッション情報を持つデータストアが停止したときと比較すれば、影響度は低いです。
では、そのセッションの情報をどうやって安全に送るのか、整合性があるのかという方法を検知できる方法としてJWTが生まれたと考えても、そこまでまちがいはないでしょう。実際には、そのトークンが改ざんされていないことを証明するようJWSやJWEなどの署名や暗号化とを組み合わせて利用しています。一般的にはこれらをまとめて便宜的にJWTと呼んでる感じですかね。
まとめ
もちろんThe Twelve-Factor Appの原理原則が正解で世界で唯一の正しいものであるとは言いませんが、開発者としては支持する母体が1つないし複数あることは重要です。そして、それに従ってステートレスなアプリケーションを作る場合には
- プロセスには何も保存しない
- 永続化が必要なデータはバックエンドのステートフルサービスを利用する
- セッション・ステートは「期限付き」データストアに保存する
であればよいということになり、古より伝承されるセッション共有の仕組みで十分ということです。そして、共有の仕組みを準備することが難しければ、JWTなどのクライアントベースのアクセストークン方式も1つの解決方法だね、ということかな。どれを採用するにしても「期限付き」であることが重要なポイントであることはまちがいないです。
基本に戻って見返してみた