14

Redis ベースのセッション ストアを実装したいと考えています。セッションデータをRedisに入れたいです。しかし、セッション期限切れの処理方法がわかりません。すべての redis キー (sessionid) をループして、最終アクセス時間と最大アイドル時間を評価できるため、すべてのキーをクライアントにロードする必要があります。公演。
有効期限をRedisに管理させたいのですが、キーの有効期限が切れたときのリスナーやコールバックがないため、HttpSessionListenerをトリガーすることができません。何かアドバイス?

4

1 に答える 1

41

そのため、Redis でセッションが期限切れになったときにアプリケーションに通知する必要があります。

Redis はこの機能をサポートしていませんが、実装に使用できるいくつかのトリックがあります。

更新: バージョン 2.8.0 から、Redis はこのhttp://redis.io/topics/notificationsをサポートします

まず、人々はそれについて考えています: これはまだ議論中ですが、Redis の将来のバージョンに追加される可能性があります。次の問題を参照してください。

ここで、現在の 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 キーの有効期限メカニズムに依存するのではなく、追加のインデックスとポーリング デーモンを使用してシミュレートすることです。変更されていない Redis 2.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 スクリプトの戻り値が空でない場合)、デーモンはすぐにループする必要があります。

Lua スクリプトのおかげで、複数のポーリング デーモンを並行して起動できます (キーは Lua スクリプト自体によって to_be_expired から削除されるため、スクリプトは特定のセッションが 1 回だけ処理されることを保証します)。

解決策 3: 外部分散タイマーを使用する

別の解決策は、外部の分散タイマーに依存することです。Beanstalk 軽量キューイング システムは、これに適した可能性があります。

システムにセッションが追加されるたびに、アプリケーションは、セッション タイムアウトに対応する遅延でセッション ID を Beanstalk キューに送信します。デーモンがキューをリッスンしています。アイテムをデキューできる場合は、セッションが期限切れになったことを意味します。Redis でセッションをクリーンアップし、アプリケーションに通知するだけです。

于 2012-08-05T10:12:52.267 に答える