poundのcookie使ったセッション管理の動作


とある事情からpoundのcookie使ったセッション管理についてちょっと詳しく調べたので、せっかくだからブログに残しておくことにした。ちなみに100%理解しているわけじゃないので、間違ってたらすまぬ。ちなみに覗いたソースはpound 2.5です。

poundといえば複数のWebサーバの前面に置きWebアクセスの負荷分散をしてくれるソフトですが、アクセスを闇雲に適当なサーバに負荷分散するとphp等で利用しているセッション機能が正常に動作しなくなります。何故なら最初に1台目Webサーバにアクセスしてセッションを有効にしても次のアクセスがまた1台目にいくとは限らず、2台目になった場合はセッション情報が取得できません。その為、1台目にリクエストされ、そこでセッションが開始されたら次のアクセス以降も必ず1台目にリクエストを投げるようにする必要があります。その方法の一つとしてpoundではcookieを使ったセッション管理機能を持ちます。

何をするかというとpoundがcookieの値を見て、「このcookieの値はさっき1台目のWebサーバにリクエストを渡したので、これも1台目にリクエストだな」という判断を行い、リクエストするWebサーバを固定させます。これでセッション機能が使えるようになります。判断対象にするcookieの値はphpで言えばセッション用のcookieであるPHPSESSIDを使えば手っ取り早いと思います。このcookie値はセッション毎にランダムの値を持つので、この値をpound側で保持して割り振るWebサーバを固定させます。また、自分で適当にセッション固定用のcookieと用意してもいいです。asp等cookie名も固定しないセッションを使う言語だったり、複数の言語が利用されているシステムでは自分で専用のcookieを用意することになるでしょう。

と、前置きはコレくらいにして本題。poundがcookieを使ったセッション管理でサーバを固定させる条件は2つあります。

 自分が一時期勘違いしてたのはサーバを固定させる条件は1つ目の「クライアントがcookie付で リクエストしてきた時」のみだと思っていた事。この場合次のような動作になる。

  1. 最初のアクセスはランダムに適当なWebサーバへリクエストされ、サーバからcookieが渡される
  2. 次のアクセスは初めてcookie付のアクセスとなり、最初のアクセスなので適当なWebサーバへリクエストされる。poundはcookie値を記憶
  3. 3回目以降のアクセスからは2回目のアクセスでサーバが固定されているので、決まったサーバへリクエストが行われる

サーバが固定されるのは2番目のアクセスから。そのため、アクセスのタイミングによっては1回目と2回目のアクセスが違うサーバになる事がある。つまり1回目のアクセスでセッションを有効にしても、2回目のアクセスで違うWebサーバにリクエストされれば、そのセッションは有効にはならない…ということになる。って事で、少々都合が悪くなるので、Webアプリ側で不都合分を色々と吸収する必要があると思っていたが、実はそんなことも無く、サーバ側からset cookieされた時にセッションを固定する事がわかったので、次のような動きが正解だった。

  1. 最初のアクセスはランダムに適当なサーバへリクエストされ、サーバからcookieが渡される。この時点でpoundはcookieを記憶
  2. 次のアクセスはcookie付のアクセスとなるが、既にcookie値は記憶されており、初回と同じWebサーバへリクエストが行われる
  3. 3回目以降は言わずもがな

ちなみにサーバ側から出力されるset cookieは毎回チェックしているので、途中でcookieの値が変わってもセッション管理はきちんと維持してくれます。 つまり次のようなアクセスでもOKです。

  1. まずWebサーバにアクセスしてたけど、しばらく放置していたのでセッションの有効期限が切れた状態とする
  2. ブラウザにはcookieが残っているので、cookie付のリクエストが行われて、poundはcookie値にしたがって特定のサーバへリクエストを投げる
  3. しかし、セッションが切れているのでWebサーバはset cookieで新しいcookieを用意するが、poundはこれを記憶。
  4. 次のアクセスは新しいcookie付で行われるが、pound側はきちんと特定のサーバへリクエストを投げる

というわけで結構考えてセッション管理をしてくれるので、アプリ側ではセッションについては特に色々考えなくてもよさそうです。ただし、複数のWebサーバが存在するのでどのサーバにアクセスしても同じ結果を返せるように「データやコンテンツの同期」の仕組みは考える必要があります。まぁそのあたりは適当に考えてみてください(投げやり)。

そしてもう一点、独自にcookieを用意してpoundにセッション管理をさせようとしている場合、そのcookieの値は完全にランダムな文字列にする必要があります。何故ならpoundがセッション管理に利用するのに「coookieの値しか見ない」からです。アクセス元のIPやAgent情報、リファラ情報も見ません。poundにはアクセス元のIPアドレスを見てセッション管理する方法もありますが、これもあくまで別のセッション管理設定です。cookieを使ったセッション管理と同時に同じbackendsに設定することはできません。

これでどのような問題が起こるかというと、別のクライアントに渡したcookieと同じ値を別のクライアントに渡した場合、poundの中では「どちらも同じセッション」とみなし、次のようにWebサーバへのアクセスがぶれてしまいます。

  1. クライアント1が session=hoge というcookieを保持し、poundはWebサーバ2へ固定リクエストを行っている
  2. クライアント2が初アクセス、poundがWebサーバ3へリクエストし、たまたま session=hoge がセットされる
  3. poundは session=hoge はWebサーバ3へ向けるように記憶する
  4. クライアント1のWebサーバが2から3に変わる

Webアプリケーションが出力するセッション用のcookieはそれなりにランダムなので、衝突する可能性は限りなく低いと思いますが、独自に実装する場合は気をつけましょう。と言っても個人的には時刻+サーバ名あたりをmd5するだけでもいいんじゃないかなとも思うけど。

というわけで、poundのcookieを利用したセッション管理の動作でした。間違ってたら誰か突っ込みください。ちなみに具体的な設定はググるか、poundのmanで確認しましょう。pound公式サイトの説明はちょっと古くてうそ書いてるところもあるし…。

余談だけど、セッション管理をpoundで行わないでWebアプリ側で何とかする方法もあります。Webアプリ側で統一したセッション管理をする方法で、DBにセッション情報を保存したり、共有ディスクにセッション情報を保存したりします。詳しくはググってください。

更に余談、上位にpoundを置いて、MODXを負荷分散させるにはどうしたらよいか。セッション管理はpoundに任せるとして、問題はコンテンツとDBの同期、キャッシュクリアの問題あたりだと思います。実際に構成したわけじゃないですが、次の方法でいけるんじゃないかと。

DBに負荷が集中しそうですが、MODXにはDBへのリクエストを抑えるキャッシュ機能があるので、存分に利用しよう。あとDB自体も負荷分散する機能とか色々あるので、それを利用するのもありかな。MODXのキャッシュクリアプラグインの簡易版は実際に作ったことあるので、これもちょっと考えれば実装できると思います。

作成日:2011/08/29 00:37:04
トラックバック  ※トラックバックは承認後に表示されます。
TrackbackURL:このページのトラックバックの受付は終了しています。

トラックバックはありません。
コメント
名前:

タイトル:

コメント: