Redis
 sql >> Datenbank >  >> NoSQL >> Redis

Wie behandelt man Sitzungsablauf basierend auf Redis?

Daher muss Ihre Anwendung benachrichtigt werden, wenn eine Sitzung in Redis abläuft.

Obwohl Redis diese Funktion nicht unterstützt, gibt es eine Reihe von Tricks, mit denen Sie sie implementieren können.

Aktualisierung:Ab Version 2.8.0 unterstützt Redis diese http://redis.io/topics/notifications

Erstens denken die Leute darüber nach:Dies wird noch diskutiert, aber es könnte zu einer zukünftigen Version von Redis hinzugefügt werden. Siehe die folgenden Probleme:

  • https://github.com/antirez/redis/issues/83
  • https://github.com/antirez/redis/issues/594

Hier sind einige Lösungen, die Sie mit den aktuellen Redis-Versionen verwenden können.

Lösung 1:Patchen von Redis

Tatsächlich ist das Hinzufügen einer einfachen Benachrichtigung, wenn Redis den Schlüsselablauf durchführt, nicht so schwierig. Es kann implementiert werden, indem der db.c-Datei des Redis-Quellcodes 10 Zeilen hinzugefügt werden. Hier ist ein Beispiel:

https://gist.github.com/3258233

Dieser kurze Patch schreibt einen Schlüssel in die #expired-Liste, wenn der Schlüssel abgelaufen ist, und beginnt mit einem '@'-Zeichen (beliebige Wahl). Es kann leicht an Ihre Bedürfnisse angepasst werden.

Es ist dann trivial, die EXPIRE- oder SETEX-Befehle zu verwenden, um eine Ablaufzeit für Ihre Sitzungsobjekte festzulegen und einen kleinen Daemon zu schreiben, der BRPOP in einer Schleife aus der "#expired"-Liste entfernt und die Benachrichtigung in Ihrer Anwendung weitergibt.

Ein wichtiger Punkt ist, zu verstehen, wie der Ablaufmechanismus in Redis funktioniert. Es gibt tatsächlich zwei verschiedene Ablaufpfade, die beide gleichzeitig aktiv sind:

  • Fauler (passiver) Mechanismus. Der Ablauf kann jedes Mal erfolgen, wenn auf einen Schlüssel zugegriffen wird.

  • Aktiver Mechanismus. Ein interner Job testet regelmäßig (zufällig) eine Reihe von Schlüsseln mit festgelegtem Ablaufdatum und versucht, diejenigen zu finden, die ablaufen.

Beachten Sie, dass der obige Patch mit beiden Pfaden gut funktioniert.

Die Folge ist, dass die Ablaufzeit von Redis nicht genau ist. Wenn alle Schlüssel abgelaufen sind, aber nur einer kurz vor dem Ablauf steht und nicht darauf zugegriffen wird, kann es mehrere Minuten dauern, bis der aktive Ablaufjob den Schlüssel findet und abgelaufen ist. Wenn Sie eine gewisse Genauigkeit bei der Benachrichtigung benötigen, ist dies nicht der richtige Weg.

Lösung 2:Ablauf mit zsets simulieren

Die Idee dabei ist, sich nicht auf den Ablaufmechanismus von Redis-Schlüsseln zu verlassen, sondern ihn zu simulieren, indem ein zusätzlicher Index und ein Polling-Daemon verwendet werden. Es kann mit einer unmodifizierten Redis 2.6-Version funktionieren.

Jedes Mal, wenn Redis eine Sitzung hinzugefügt wird, können Sie Folgendes ausführen:

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

Die sortierte Menge to_be_expired ist nur ein effizienter Weg, um auf die ersten Schlüssel zuzugreifen, die ablaufen sollten. Ein Daemon kann to_be_expired unter Verwendung des folgenden serverseitigen Lua-Skripts abfragen:

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

Der Befehl zum Starten des Skripts wäre:

EVAL <script> 1 to_be_expired <current timestamp>

Der Daemon bekommt höchstens 10 Items. Für jede von ihnen muss es den DEL-Befehl verwenden, um die Sitzungen zu entfernen und die Anwendung zu benachrichtigen. Wenn ein Element tatsächlich verarbeitet wurde (d. h. die Rückgabe des Lua-Skripts ist nicht leer), sollte der Daemon sofort eine Schleife durchlaufen, andernfalls kann ein Wartezustand von 1 Sekunde eingeführt werden.

Dank des Lua-Skripts ist es möglich, mehrere Polling-Daemons parallel zu starten (das Skript garantiert, dass eine bestimmte Sitzung nur einmal verarbeitet wird, da die Schlüssel von to_be_expired durch das Lua-Skript selbst entfernt werden).

Lösung 3:Verwenden Sie einen externen verteilten Timer

Eine andere Lösung besteht darin, sich auf einen externen verteilten Zeitgeber zu verlassen. Das Beanstalk Lightweight Queuing System ist dafür eine gute Möglichkeit

Jedes Mal, wenn dem System eine Sitzung hinzugefügt wird, sendet die Anwendung die Sitzungs-ID mit einer Verzögerung, die dem Sitzungs-Timeout entspricht, an eine Beanstalk-Warteschlange. Ein Daemon überwacht die Warteschlange. Wenn ein Element aus der Warteschlange entfernt werden kann, bedeutet dies, dass eine Sitzung abgelaufen ist. Es muss nur die Sitzung in Redis bereinigen und die Anwendung benachrichtigen.