Така че трябва вашето приложение да бъде уведомено, когато сесията изтече в 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 извършва изтичане на ключ, не е толкова трудно. Може да се реализира чрез добавяне на 10 реда към файла db.c на изходния код на Redis. Ето един пример:
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 е просто ефективен начин за достъп до първите ключове, които трябва да изтекат. Демон може да анкетира to_be_expired, използвайки следния Lua скрипт от страна на сървъра:
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 е възможно паралелно стартиране на няколко демона за запитване (скриптът гарантира, че дадена сесия ще бъде обработена само веднъж, тъй като ключовете се премахват от to_be_expired от самия Lua скрипт).
Решение 3:използвайте външен разпределен таймер
Друго решение е да разчитате на външен разпределен таймер. Олекотената система за опашка на бобови стъбла е добра възможност за това
Всеки път, когато се добави сесия в системата, приложението публикува идентификатора на сесията в опашка на beanstalk със закъснение, съответстващо на времето за изчакване на сесията. Демон слуша опашката. Когато може да извади елемент от опашката, това означава, че сесията е изтекла. Просто трябва да почисти сесията в Redis и да уведоми приложението.