ちょっとした温故知新
■セッションとその問題
Webシステムにおいて、1つの取引情報(=ここでは、これをトランザクションとす
る)が数画面に渡るときが有る。このような場合、データ(ここでは取引情報)をセッ
ションに入れておく。この方法は、いまだに変わっていない。
しかし以下のケースでは問題が起こる。
・負荷分散させた場合
・障害時
・タブブラウザ対応
●「負荷分散させた場合」について。
例えばTomcatをA,B,Cという3台で走らせていたとする。そこに、Xさんがアクセスし
たとき、Xさんが、TomcatAにアクセスし、TomcatA上にセッションを作成した場合、次
からアクセスは、TomcatAにしかアクセスできない。B,CからAのセッションを見れない
から。つまり、セッションを作成した場合、トランザクション中は、他のマシンに分散
できなくなる。
●「障害時」について
このとき、セッション情報も吹っ飛ぶ。
したがって、TomcatをA,B,Cという3台で走らせていたとする。そこに、Xさんがアク
セスしたとき、Xさんが、TomcatAにアクセスし、TomcatA上にセッションを作成したの
ち、Aのマシンが壊れた場合、Aのマシンに有るXさんのセッションも吹っ飛ぶ。したが
って、B,Cが処理可能だとしても、Xさんは、データを入れなおさないといけない。
●「タブブラウザ対応」
IEの場合、同一ブラウザでは、違うタブで開いても、同一のセッションになる。した
がって、ログイン後、「処理をいろいろした後」に、新しいタブを開いて、再度ログイ
ンしなおそうとしても、新しいタブは、「処理をいろいろした後」のセッション情報が
共有される
■問題解決としてのSession in DBと新たな問題
この問題を解決する方法として、セッションデータをファイルまたはDBに落とすとい
う方法が考案された。
つまり、以下のようにする
・ログイン時に、唯一のIDを振る
(今回は、これをトランザクションIDと呼ぶ。この説明用であり、
一般的な言い方ではない)
そして、ログイン時にセッションに入れたいような内容は、
トランザクションIDをキーとして、(ファイルの場合ファイル名として)
DB、ファイルに書き込む。
次画面から、「必ず」このトランザクションIDをhiddenで送る。
・ログイン後、画面遷移する際、セッションを生成する箇所をラップし、
セッションを生成するときに、
トランザクションIDを引数から取り出し
(hiddenで必ず送る=必ず引数に入っている)
トランザクションIDを元に、前の画面のセッション内容を
DB、ファイルから取り出し、
セッション内容を、そのDB、ファイルの内容に書き換える
セッションに何か書き込むところもラップし、
セッションに書き込むと共に、
トランザクションIDをもとに、セッション内容を
DB、ファイルに書き込む
→画面終了時に書きこんでも良い。
このように、セッションを使うときのコーディング規約を決めて、
守らせる
・ログアウト時、トランザクションIDを元に、データを削除する。
また、一定時間アクセスのないものは、データを削除する
→バッチで消してもいいし、だれかがセッションを生成したときに、
いらないものを(他の人のものを含め消してしまう)
そして、セッションを書き込むファイルまたはDBは、どのTomcatでも
参照できるようにする。そうすると、
○TomcatAでXさんが作ったセッションは、トランザクションID 00001で
ファイルに保存されたとすると、
・そのあと、負荷分散で、TomcatBでXさんのデータを処理しようとしたとき、
送信内容にトランザクションID 00001と入っているので、XさんのAマシン
でやった処理が継続される
・障害で、TomcatAからTomcatBで変わっても同じ
・タブブラウザの場合。
はじめのタブでログインすると、トランザクションID 00001で処理
される。タブを新たに開いてログインすると、トランザクションID
00002とか、違う番号で振られる。セッションはトランザクションID
に基づいて、サーバー側で入れ替えられるから、大丈夫・・・
・・・かって言うと、実はそうではなく、セッションは排他制御
されない(たしか)。なので、この場合は、セッションに入れ替える
のではなく、トランザクションIDをもとに、セッションを作り直したり、
セッションに変わるデータ領域で頑張るなど、ちょっと工夫が居る。
しかし、このような工夫はラップされているので、見えない
→操作する人は、セッションと同じように操作できる。
ということで、めでたしめでたし。
とくにこのとき、DBにセッションデータを入れる方法を
Session in DBといった(と思う)
しかし、DBに入れる場合に問題が起きた
・DBに障害が起きたら?
・DBのアクセス数が増えることに問題はないのか?
つまり、この方法は、画面アクセスごとに、セッションデータの検索、
更新ごとに(ないしは画面アクセスごとに)セッションデータの保存
が起こる。検索時は検索データがネットワークに流れ、保存時は、
データがDBのほか、ログ(ジャーナル)にも書かれる。
この量がはんぱない場合、この手法は問題で、DBへのリスクを増やしかねない。
そして、DBに障害が起きたら、使えないジャン
という問題が起きた。
■NoSQLの利用
そこで、データを保存するDBとは別に、データを保管する場所を
持とうということになった。
この場合、NoSQLを利用して、単一の障害点をなくすようにしたり
することもできる。
インメモリDBだと、処理スピードもあがるとか期待できるかもしれない
Cassandraとかmemcachedの利用が考えられる。
しかし、この場合も問題がある。
CassandraのようなJavaで動くものの場合、
TomcatもCassandraもなんでもかんでもすべて・・・
となると、メモリが半端なく消費され、
フルガベージコレクションが起こる・・・と遅くなるし、
これを繰り返すと、最悪out of memoryになったりする。
■問題点と現状
フルガベージコレクションが起こることに対しては、
Interstageなどでは、予測して負荷分散する機能があるらしい。
ただ、遅くても大丈夫そうな場合、ファイルシステムをつかったり、
1箇所にデータアクセスが固まらないように、保存するセッションデータを
複数にわけて、シャーディングするなど、いろいろと、工夫の余地はありそうだ。
■セッションとその問題
Webシステムにおいて、1つの取引情報(=ここでは、これをトランザクションとす
る)が数画面に渡るときが有る。このような場合、データ(ここでは取引情報)をセッ
ションに入れておく。この方法は、いまだに変わっていない。
しかし以下のケースでは問題が起こる。
・負荷分散させた場合
・障害時
・タブブラウザ対応
●「負荷分散させた場合」について。
例えばTomcatをA,B,Cという3台で走らせていたとする。そこに、Xさんがアクセスし
たとき、Xさんが、TomcatAにアクセスし、TomcatA上にセッションを作成した場合、次
からアクセスは、TomcatAにしかアクセスできない。B,CからAのセッションを見れない
から。つまり、セッションを作成した場合、トランザクション中は、他のマシンに分散
できなくなる。
●「障害時」について
このとき、セッション情報も吹っ飛ぶ。
したがって、TomcatをA,B,Cという3台で走らせていたとする。そこに、Xさんがアク
セスしたとき、Xさんが、TomcatAにアクセスし、TomcatA上にセッションを作成したの
ち、Aのマシンが壊れた場合、Aのマシンに有るXさんのセッションも吹っ飛ぶ。したが
って、B,Cが処理可能だとしても、Xさんは、データを入れなおさないといけない。
●「タブブラウザ対応」
IEの場合、同一ブラウザでは、違うタブで開いても、同一のセッションになる。した
がって、ログイン後、「処理をいろいろした後」に、新しいタブを開いて、再度ログイ
ンしなおそうとしても、新しいタブは、「処理をいろいろした後」のセッション情報が
共有される
■問題解決としてのSession in DBと新たな問題
この問題を解決する方法として、セッションデータをファイルまたはDBに落とすとい
う方法が考案された。
つまり、以下のようにする
・ログイン時に、唯一のIDを振る
(今回は、これをトランザクションIDと呼ぶ。この説明用であり、
一般的な言い方ではない)
そして、ログイン時にセッションに入れたいような内容は、
トランザクションIDをキーとして、(ファイルの場合ファイル名として)
DB、ファイルに書き込む。
次画面から、「必ず」このトランザクションIDをhiddenで送る。
・ログイン後、画面遷移する際、セッションを生成する箇所をラップし、
セッションを生成するときに、
トランザクションIDを引数から取り出し
(hiddenで必ず送る=必ず引数に入っている)
トランザクションIDを元に、前の画面のセッション内容を
DB、ファイルから取り出し、
セッション内容を、そのDB、ファイルの内容に書き換える
セッションに何か書き込むところもラップし、
セッションに書き込むと共に、
トランザクションIDをもとに、セッション内容を
DB、ファイルに書き込む
→画面終了時に書きこんでも良い。
このように、セッションを使うときのコーディング規約を決めて、
守らせる
・ログアウト時、トランザクションIDを元に、データを削除する。
また、一定時間アクセスのないものは、データを削除する
→バッチで消してもいいし、だれかがセッションを生成したときに、
いらないものを(他の人のものを含め消してしまう)
そして、セッションを書き込むファイルまたはDBは、どのTomcatでも
参照できるようにする。そうすると、
○TomcatAでXさんが作ったセッションは、トランザクションID 00001で
ファイルに保存されたとすると、
・そのあと、負荷分散で、TomcatBでXさんのデータを処理しようとしたとき、
送信内容にトランザクションID 00001と入っているので、XさんのAマシン
でやった処理が継続される
・障害で、TomcatAからTomcatBで変わっても同じ
・タブブラウザの場合。
はじめのタブでログインすると、トランザクションID 00001で処理
される。タブを新たに開いてログインすると、トランザクションID
00002とか、違う番号で振られる。セッションはトランザクションID
に基づいて、サーバー側で入れ替えられるから、大丈夫・・・
・・・かって言うと、実はそうではなく、セッションは排他制御
されない(たしか)。なので、この場合は、セッションに入れ替える
のではなく、トランザクションIDをもとに、セッションを作り直したり、
セッションに変わるデータ領域で頑張るなど、ちょっと工夫が居る。
しかし、このような工夫はラップされているので、見えない
→操作する人は、セッションと同じように操作できる。
ということで、めでたしめでたし。
とくにこのとき、DBにセッションデータを入れる方法を
Session in DBといった(と思う)
しかし、DBに入れる場合に問題が起きた
・DBに障害が起きたら?
・DBのアクセス数が増えることに問題はないのか?
つまり、この方法は、画面アクセスごとに、セッションデータの検索、
更新ごとに(ないしは画面アクセスごとに)セッションデータの保存
が起こる。検索時は検索データがネットワークに流れ、保存時は、
データがDBのほか、ログ(ジャーナル)にも書かれる。
この量がはんぱない場合、この手法は問題で、DBへのリスクを増やしかねない。
そして、DBに障害が起きたら、使えないジャン
という問題が起きた。
■NoSQLの利用
そこで、データを保存するDBとは別に、データを保管する場所を
持とうということになった。
この場合、NoSQLを利用して、単一の障害点をなくすようにしたり
することもできる。
インメモリDBだと、処理スピードもあがるとか期待できるかもしれない
Cassandraとかmemcachedの利用が考えられる。
しかし、この場合も問題がある。
CassandraのようなJavaで動くものの場合、
TomcatもCassandraもなんでもかんでもすべて・・・
となると、メモリが半端なく消費され、
フルガベージコレクションが起こる・・・と遅くなるし、
これを繰り返すと、最悪out of memoryになったりする。
■問題点と現状
フルガベージコレクションが起こることに対しては、
Interstageなどでは、予測して負荷分散する機能があるらしい。
ただ、遅くても大丈夫そうな場合、ファイルシステムをつかったり、
1箇所にデータアクセスが固まらないように、保存するセッションデータを
複数にわけて、シャーディングするなど、いろいろと、工夫の余地はありそうだ。