我想實現基於redis的會話存儲,我將會話數據放入redis中。但我不知道如何處理session-expire。我可以循環所有redis鍵(sessionid)並且忽略lastaccess和maxidle數據,因此我需要將所有密鑰加載到客戶端,並且可能有1000m會話密鑰,並且可能會導致非常池I/O性能。
我想讓redis管理到期,但是當key過期時沒有監聽器或回調,所以不可能老虎HttpSessionListener。 有什麼建議嗎?如何處理基於redis的會話過期?
回答
因此,您需要在Redis會話過期時通知您的應用程序。
雖然Redis不支持此功能,但您可以使用一些技巧來實現它。
更新:從2.8.0版本,Redis的不支持此http://redis.io/topics/notifications
首先,人們都在考慮這個問題:這個還在討論中,但它可能會被添加到Redis的未來版本。請參見下面的問題:
現在,這裏有一些解決方案可以與目前Redis的版本使用。
解決方案1:修補的Redis
實際上,增加一個簡單的通知時執行的Redis密鑰過期並不難。它可以通過將10行添加到Redis源代碼的db.c文件中來實現。這裏有一個例子:
https://gist.github.com/3258233
這個簡短的帖子補丁的#expired列表中的關鍵,如果密鑰已過期,並用「@」字符(任意選擇)開始。它可以很容易地適應您的需求。
然後使用EXPIRE或SETEX命令爲會話對象設置過期時間,然後編寫一個循環BRPOP的小守護程序以從「#expired」列表中出列,並在您的應用。
重要的一點是要了解到期機制如何在Redis中起作用。實際上有兩種到期的不同路徑,兩者都同時激活:
懶惰(被動)機制。每次訪問密鑰時都可能發生到期。
主動機制。內部工作會定期(隨機)對設置了過期時間的許多密鑰進行採樣,試圖找出過期的密鑰。
請注意,上述補丁適用於兩個路徑。
後果是Redis過期時間不準確。如果所有密鑰都已過期,但只有一個即將過期,並且未被訪問,則活動的過期作業可能需要幾分鐘的時間才能找到密鑰並過期。如果您在通知中需要一些準確性,這不是要走的路。
解決方法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排序set只是訪問應該到期的第一密鑰的有效途徑。守護程序可以輪詢使用以下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命令刪除會話,並通知應用程序。如果實際處理了一個項目(即Lua腳本的返回非空),守護程序應該立即循環,否則可引入1秒的等待狀態。
得益於Lua腳本,可以同時啓動多個輪詢守護程序(腳本保證給定的會話只處理一次,因爲這些鍵由Lua腳本本身從to_be_expired中移除)。
解決方案3:使用外部分佈式計時器
另一種解決方案是依靠外部分佈式定時器。 beanstalk lightweight queuing system對此很有可能
每次在系統中添加會話時,應用程序都會將會話ID過帳到豆桶隊列,延遲時間與會話超時相對應。守護進程正在監聽隊列。當它可以使項目出列時,這意味着會話已經過期。它只需在Redis中清理會話並通知應用程序。
令人驚歎的答案 - 非常感謝!你能否澄清這句話:「守護進程應立即循環,否則可引入1秒等待狀態」。在這種情況下,循環意味着什麼 - 爲什麼/在哪裏等待1秒等待? – 2013-07-02 14:05:14
守護進程是常駐程序,有時候會在系統中進行某些活動。由於它們一直在運行,大部分代碼都被封裝在主循環中。現在守護進程還需要一個等待狀態,以避免循環時佔用100%的CPU。沒有與Redis的zset關聯的阻塞命令(與列表中的BLPOP/BRPOP不同),所以如果沒有返回任何內容,它必須通過輪詢和睡眠來模擬。 – 2013-07-02 20:37:02
這已經在redis中實現。這些問題已經結束。如果有人更新了這個答案,那將會很好。 – 2014-04-19 14:44:41
- 1. 處理過期的會話
- 2. Shiro過期會話處理
- 3. Tomcat會話過期處理
- 4. 如何處理在Django中API會話過期的會話?
- 5. Node/Express with connect-redis,如何處理會話到期
- 6. 基於Django密鑰的會話過期
- 7. 基於環回redis的會話
- 8. 處理會話過期的iOS HTTPRequest
- 9. 會話過期時基於數據庫的基於會話的乾淨數據
- 10. 在基於Spring的Web應用程序中處理會話過期事件
- 11. 你會如何處理Facebook會話過期?
- 12. 處理會話過期異常
- 13. 如何使用spring-security和jQuery處理過期的會話?
- 14. 如何處理會話過期時JSP中的異常?
- 15. 如何在會話過期時處理laravel TokenMismatchException
- 16. 如何處理PHP Facebook會話過期異常?
- 17. 混合身份驗證 - 會話過期如何處理?
- 18. .net mvc&ajax表單 - 如何處理會話過期
- 19. Quickblox會話在後臺過期。如何處理它?
- 20. 如何實現redis會話在aiohttp中過期
- 21. ember.js - 如何處理會話
- 22. 如何處理會話php
- 23. 如果會話已過期,處理AJAX請求
- 24. Rails基於cookie的會話:混合會話範圍和過期時間
- 25. 基於令牌的會話管理
- 26. 如何使用Flask-KVSession管理清理過期的會話?
- 27. Laravel 4 - auth.basic過濾器會話不會過期|如何過期auth.basic會話
- 28. 處理會話
- 29. 處理會話
- 30. 處理會話
不是在Redis中,但你可能想看看它是如何在Tarantool中完成的: https://github.com/mailru/tntlua/blob/master/expirationd.lua 簡而言之,在Tarantool中你可以在數據庫中運行自己的Lua腳本,並在其中設置自己的過期策略。不需要外部守護進程。 – Kostja 2013-05-03 11:38:15