そのため、Redisでセッションが期限切れになったときにアプリケーションに通知する必要があります。
Redisはこの機能をサポートしていませんが、この機能を実装するために使用できるトリックがいくつかあります。
更新:バージョン2.8.0以降、Redisはこのhttp://redis.io/topics/notificationsをサポートします
まず、人々はそれについて考えています。これはまだ議論中ですが、Redisの将来のバージョンに追加される可能性があります。次の問題を参照してください:
- https://github.com/antirez/redis/issues/83
- https://github.com/antirez/redis/issues/594
ここに、現在のRedisバージョンで使用できるいくつかのソリューションがあります。
解決策1:Redisにパッチを適用する
実際、Redisがキーの有効期限を実行するときに単純な通知を追加することはそれほど難しくありません。これは、Redisソースコードのdb.cファイルに10行を追加することで実装できます。次に例を示します:
https://gist.github.com/3258233
この短いパッチは、キーの有効期限が切れて「@」文字で始まる場合に、キーを#expiredリストに投稿します(任意の選択)。ニーズに簡単に合わせることができます。
次に、EXPIREまたはSETEXコマンドを使用してセッションオブジェクトの有効期限を設定し、BRPOPでループして「#expired」リストからデキューし、アプリケーションで通知を伝播する小さなデーモンを作成するのは簡単です。
重要な点は、Redisで有効期限メカニズムがどのように機能するかを理解することです。実際には、有効期限には2つの異なるパスがあり、両方が同時にアクティブになります。
-
怠惰な(パッシブ)メカニズム。有効期限は、キーにアクセスするたびに発生する可能性があります。
-
アクティブなメカニズム。内部ジョブは、有効期限が設定された多数のキーを定期的に(ランダムに)サンプリングし、有効期限が切れるキーを見つけようとします。
上記のパッチは両方のパスで正常に機能することに注意してください。
その結果、Redisの有効期限は正確ではありません。すべてのキーに有効期限があり、1つだけが有効期限が切れようとしていて、アクセスされていない場合、アクティブな有効期限ジョブがキーを見つけて有効期限が切れるまでに数分かかる場合があります。通知にある程度の正確さが必要な場合、これは進むべき道ではありません。
解決策2:zsetsを使用して有効期限をシミュレートする
ここでの考え方は、Redisキーの有効期限メカニズムに依存するのではなく、追加のインデックスとポーリングデーモンを使用してシミュレートすることです。変更されていないRedis2.6バージョンで動作します。
セッションがRedisに追加されるたびに、以下を実行できます:
MULTI
SET <session id> <session content>
ZADD to_be_expired <current timestamp + session timeout> <session id>
EXEC
to_be_expiredソート済みセットは、期限切れになる最初のキーにアクセスするための効率的な方法にすぎません。デーモンは、次のLuaサーバー側スクリプトを使用してto_be_expiredをポーリングできます。
local res = redis.call('ZRANGEBYSCORE',KEYS[1], 0, ARGV[1], 'LIMIT', 0, 10 )
if #res > 0 then
redis.call( 'ZREMRANGEBYRANK', KEYS[1], 0, #res-1 )
return res
else
return false
end
スクリプトを起動するコマンドは次のようになります:
EVAL <script> 1 to_be_expired <current timestamp>
デーモンは最大10個のアイテムを取得します。それぞれについて、DELコマンドを使用してセッションを削除し、アプリケーションに通知する必要があります。 1つのアイテムが実際に処理された場合(つまり、Luaスクリプトの戻り値が空でない場合)、デーモンはすぐにループする必要があります。そうでない場合、1秒の待機状態が発生する可能性があります。
Luaスクリプトのおかげで、複数のポーリングデーモンを並行して起動することができます(スクリプトは、Luaスクリプト自体によってto_be_expiredからキーが削除されるため、特定のセッションが1回だけ処理されることを保証します)。
解決策3:外部分散タイマーを使用する
別の解決策は、外部分散タイマーに依存することです。 Beanstalkの軽量キューイングシステムは、このための良い可能性です
システムにセッションが追加されるたびに、アプリケーションはセッションIDをbeanstalkキューに送信し、セッションのタイムアウトに対応する遅延を発生させます。デーモンがキューをリッスンしています。アイテムをデキューできる場合は、セッションが期限切れになったことを意味します。 Redisでセッションをクリーンアップし、アプリケーションに通知するだけです。