2012-08-04 13 views
13

Chcę zaimplementować sesję-sklep bazując na Redis, umieszczam dane sesji w Redis. Ale nie wiem, jak sobie poradzić z sesją-expire. Mogę zapętlić wszystkie klucze redis (sessionid) i ewakuować dane lastaccess i maxidle, więc potrzebuję załadować wszystkie klucze do klienta i może jest to 1000m kluczy sesji i może prowadzić bardzo wydajną wydajność we/wy puli.
Chcę, aby redis zarządzał wygaśnięciem, ale nie ma słuchacza ani wywołania zwrotnego, gdy klucz wygasa, więc niemożliwe jest dla tygrysa HttpSessionListener. jakiejkolwiek porady?jak obsłużyć sesję wygasającą w oparciu o redis?

+0

Nie w Redis, ale może warto przyjrzeć się, jak to się robi w Tarantool: https://github.com/mailru/tntlua/blob/master/expirationd.lua W skrócie, w Tarantool ciebie może uruchamiać własne skrypty Lua w bazie danych i ustawiać w nich własne reguły wygasania. Nie są potrzebne zewnętrzne demony. – Kostja

Odpowiedz

33

Potrzebujesz aplikacji do powiadomienia, gdy sesja wygasa w Redis.

Podczas gdy Redis nie obsługuje tej funkcji, istnieje kilka sztuczek, których możesz użyć do jej implementacji.

Update: Od wersji 2.8.0, Redis obsługuje ten http://redis.io/topics/notifications

Po pierwsze, ludzie myślą o tym: to jest nadal przedmiotem dyskusji, ale może być dodany do przyszłej wersji Redis. Zobacz następujące zagadnienia:

Teraz, oto niektóre rozwiązania można korzystać z bieżącej wersji Redis.

Rozwiązanie 1: łatanie Redis

Faktycznie, dodając prosty powiadomienie gdy Redis wykonuje kluczową wygaśnięcie nie jest takie trudne. Można go zaimplementować, dodając 10 wierszy do pliku db.c kodu źródłowego Redis. Oto przykład:

https://gist.github.com/3258233

Ten krótki posty krosowe klucza do listy #expired jeśli klucz wygasł i rozpoczyna się od znaku „@” (arbitralny wybór). Można go łatwo dostosować do Twoich potrzeb.

Używanie poleceń EXPIRE lub SETEX do ustawiania czasu wygaśnięcia obiektów sesji jest banalne i napisanie małego demona pętlą na BRPOP w celu usunięcia z listy "#expired" i propagacji powiadomienia podanie.

Ważne jest, aby zrozumieć, w jaki sposób mechanizm wygaśnięcia działa w Redis. W rzeczywistości istnieją dwie różne ścieżki wydechu, obie aktywne w tym samym czasie:

  • Mechanizm leniwy (pasywny). Wygaśnięcie może nastąpić za każdym razem, gdy klucz jest dostępny.

  • Aktywny mechanizm. Wewnętrzne zadanie regularnie (losowo) pobiera kilka kluczy z zestawem do wygaśnięcia, próbując znaleźć te, które wygasną.

Należy zauważyć, że powyższa łatka działa dobrze z obiema ścieżkami.

Konsekwencją jest czas wygaśnięcia Redis nie jest dokładny.Jeśli wszystkie klucze mają wygaśnięcie, ale tylko jeden ma wygasnąć, a dostęp do niego nie jest możliwy, aktywne zadanie wygaśnięcia może zająć kilka minut, aby znaleźć klucz i stracił ważność. Jeśli potrzebujesz dokładności w powiadomieniu, nie jest to właściwa droga.

Rozwiązanie 2: symulowanie ważności z zsets

Chodzi o to, aby nie polegać na kluczowy mechanizm wygaśnięcia Redis, ale zasymulować za pomocą dodatkowego indeksu plus demona odpytywania. Może pracować z niezmodyfikowaną wersją Redis 2.6.

każdym razem, gdy sesja jest dodawany do Redis, można uruchomić:

MULTI 
SET <session id> <session content> 
ZADD to_be_expired <current timestamp + session timeout> <session id> 
EXEC 

to_be_expired klasyfikowane zestaw jest tylko skutecznym sposobem dostępu pierwsze klucze, które powinny być wygasł. Demon może odpytywać na to_be_expired stosując następujący Lua skrypt po stronie serwera:

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 

komendę, aby uruchomić skrypt będzie:

EVAL <script> 1 to_be_expired <current timestamp> 

Demon dostanie co najwyżej 10 pozycji. Dla każdego z nich musi użyć polecenia DEL, aby usunąć sesje i powiadomić aplikację. Jeśli jeden element został faktycznie przetworzony (tj. Zwrot skryptu Lua nie jest pusty), demon powinien natychmiast wykonać pętlę, w innym przypadku można wprowadzić stan oczekiwania na 1 sekundę.

Dzięki skryptowi Lua możliwe jest równoległe uruchamianie kilku demów (skrypt gwarantuje, że dana sesja zostanie przetworzona tylko raz, ponieważ klucze są usuwane z to_be_expired przez sam skrypt Lua).

Roztwór 3: wykorzystanie zewnętrznego rozmieszczone czasowy

Innym rozwiązaniem jest poleganie na zewnętrznym rozproszonego czasowego. beanstalk lightweight queuing system jest dobrą możliwością dla tego

Za każdym razem, gdy sesja zostanie dodana do systemu, aplikacja wysyła identyfikator sesji do kolejki beanstralk z opóźnieniem odpowiadającym limitowi czasu sesji. Demon słucha kolejki. Kiedy może ponownie usunąć element, oznacza to, że sesja wygasła. Wystarczy wyczyścić sesję w Redis i powiadomić aplikację.

+0

Niesamowita odpowiedź - wielkie dzięki! Czy możesz wyjaśnić to zdanie: "demon powinien się zapętlić natychmiast, w przeciwnym razie można wprowadzić stan oczekiwania na 1 sekundę". Co oznacza pętla w tym kontekście - i dlaczego/gdzie jest to 1 sekunda oczekiwania? –

+0

Demony są programami rezydentnymi, które czasami budzą się, aby wykonać pewne czynności w systemie. Ponieważ ciągle działają, większość kodu jest zamknięta w pętli głównej. Teraz demon potrzebuje również stanu oczekiwania, aby uniknąć przyjmowania 100% procesora podczas pętli. Nie ma polecenia blokującego powiązanego z zset z Redis (w przeciwieństwie do BLPOP/BRPOP dla listy), więc musi zostać zasymulowany przez sondowanie i spanie, jeśli nic nie jest zwracane. –

+2

To jest już zaimplementowane w trybie redis. Te problemy są zamknięte. Byłoby miło, gdyby ktoś zaktualizował tę odpowiedź. –

Powiązane problemy