Session-Management

Was ist ein Session-Status?

Unter dem Begriff Session-Status versteht man Daten, die den aktuellen Zustand von Benutzerinteraktionen mit Anwendungen, beispielsweise einer Website oder einem Spiel, erfassen.

Eine typische Webanwendung hält eine Session für jeden verbundenen Benutzer solange aufrecht, wie der Benutzer eingeloggt ist. Mithilfe des Session-Status erinnern sich Apps an Informationen wie Benutzeridentitäten, Login-Anmeldedaten, persönliche Informationen, die letzten Aktionen und den Inhalt des Einkaufswagen.

Das Lesen und Schreiben der Sessionsdaten darf die Nutzererfahrung nicht stören. Der Session-Status besteht aus gecachten Daten eines spezifischen Benutzers oder einer spezifischen Anwendung. Dadurch wird eine schnelle Reaktion auf Benutzeraktionen ermöglicht. Während der Nutzer aktiv ist, ist deshalb kein Zugriff auf die zentrale Datenbank notwendig.

Ein Session-Status endet, wenn der Benutzer die Verbindung trennt. Einige Daten werden für den zukünftigen Gebrauch gespeichert, die flüchtigen Daten können jedoch nach der Beendigung der Session gelöscht werden.

Herausforderungen und bewährte Praktiken für den Session-Status

Es ist wichtig, die bewährten Praktiken für den Session-Status zu verstehen, um allgemeine Session-bezogener Probleme, wie Isolierung, Flüchtigkeit und Persistenz, richtig bewerten und lösen zu können.

Während die Session läuft, liest die Anwendung aus dem In-Memory-Session-Speicher und schreibt ausschließlich in diesen Speicher. Das führt zu schnelleren Schreibvorgängen, aber bedeutet auch, dass keine Toleranz gegenüber Datenverlust vorliegt. Da es sich bei Session-Speicherdaten nicht einfach um eine Momentaufnahme von einer anderen Datenbank handelt, müssen sie langlebig und immer verfügbar sein.

Ein Session-Status entspricht einem Cache. Er hat jedoch unterschiedliche Lese-/Schreib-Lebenszyklen: ein Cache ist tolerant gegenüber Datenverlust und kann jederzeit von einer primären Datenbank aus wiederhergestellt werden. Wenn in einen Cache geschrieben wird, muss auch in die ihm zugrundeliegende Datenbank geschrieben werden. Der Session-Status hingegen kann nur aus der primären Datenquelle wiederhergestellt werden und wird erst zur persistenten Datenquelle zurückgeführt, wenn die Session endet.

Ein Session-Status kann flüchtig oder permanent sein. Das bedeutet, dass Daten entweder entfernt werden oder auf dem Datenspeicher gespeichert werden, wenn die Benutzer-Session endet. Ein Beispiel flüchtiger Session-Daten ist der Navigationsverlauf im Intranet eines Unternehmens. Hier macht es wenig Sinn, diese Daten zu speichern. Im Kontrast dazu steht der Einkaufswagen in einer E-Commerce-App. Es ist für das Geschäft wichtig, dass die Daten erhalten bleiben und sie in einem permanenten Speicher gesichert sind.

Ein Session-Status wird als Schlüssel-Wert-Paar mit der Benutzerkennung als Schlüssel und den Sessionsdaten als Wert gespeichert. Das garantiert, dass Benutzersessions nicht gegenseitig auf die Informationen der anderen Session zugreifen.

Das Speichern des Session-Status in einem schnellen In-Memory-Cache ermöglicht analytische Szenarien, die eine transaktionale Datenbank normalerweise abstrafen würde. Diese Anwendungen umfassen Echtzeit-Analysen und Dashboards, Empfehlungsmaschinen und Betrugserkennung.

Wie Redis Enterprise bei der Beschleunigung hilft

Anwendung von Redis Enterprise für Session-Management

Stellen Sie sich zum Beispiel eine Text-Chat-Anwendung vor mit MySQL als relationale Datenbank, Node.js als Backend-Server-Technologie und Redis Enterprise für Session-Management. Das Frontend besteht aus zwei Seiten: aus einer Startseite, auf der Benutzer sich einloggen, und aus einer Chatseite, auf der Benutzer Nachrichten eingeben und versenden.

Der Einfachheit halber zeigen wir Ihnen hier nur den Servercode. Er erklärt, wie man den Session-Status-Lebenszyklus in Node.js implementiert. Wir lassen auch die HTML-Ansichtsseiten und den Rest der Anwendung weg.

Zuerst lädt die Anwendung Abhängigkeiten, wie Sessions, Redis Objekte und MySQL-Client:

var express = require("express");
var session = require('express-session');
var mysql = require("mysql");
var redis = require("redis");
var redisStore = require('connect-redis')(session);
var redisClient = redis.createClient();
// mehr Abhängigkeiten werden hier geladen...

Die obigen Deklarationen erstellen Objekte für die Verwaltung von Web-Routing, Sessions, Datenbanken, Caching und Node.js Sessions-Bibliotheken. Dann legen Sie Redis als Session-Speicher fest:

app.use(session({
secret: 'mysecret',
// neuen Redis Speicher erstellen.
store: new redisStore({ host: 'localhost', port: 6379, client: redisClient }),
saveUninitialized: false,
resave: false
}));

Konfigurieren Sie dann die Node.js Expressrouten für die Start- und Chatseite mit der Unterstützung für AJAX-Anfragen, die vom Kunden kommen, wie Login, Logout und Versand von Kommentaren.

Wenn ein Benutzer die Startseite anfragt, leitet der Server ihn direkt auf die chat.html-Seite weiter oder zeigt die Login-Seite.html an, je nachdem, ob der Benutzer eingeloggt ist oder nicht. Der Snippet weiter unten zeigt den Anwendercode für die /get-Webroute:

app.get('/',function(req,res){
app.get('/',function(req,res){
// neues Sessions-Objekt erstellen.
if(req.session.key) {
// Benutzer ist bereits eingeloggt
res.redirect('/chat');
} else {
// es konnte keine Session gefunden werden, gehen Sie zur Login-Seite
res.render("login.html");
}
});

Wenn der Benutzer die Login-Formulardaten (mit E-Mail-Adresse und Passwort) einreicht, sendet der Client JavaScript AJAX Formulardaten an den Server. In diesem Beispiel geht der Aufruf an die executeLoginDbCommand – Funktion (wird hier nicht angezeigt), die eine SQL-Anfrage gegen die MySQL-Datenbank ausführt und ein Objekt mit den vorher von dem Benutzer gespeicherten Sessions-Daten zurücksendet.

Wenn der Login erfolgreich ist, werden die Benutzerdaten von MySQL mithilfe des Redis Sessions-Speicher in der Websession gespeichert. Der Client-JavaScript-Code leitet den Benutzer weiter auf die Chatseite:

app.post('/login',function(req, res){
// SQL-Anfrage vergleicht Login und Passwort
// von HTTP-Anfrage-Inhalt mit Benutzer-Tabellendaten
executeLoginDbCommand(req.body.Email, req.body.Password, function(dbResult){
//
if(!dbResult) {
res.json({"success" : false,"message" : "Login ist fehlgeschlagen! Bitte registrieren"});
} else {
req.session.key = dbResult;
res.json({"success" : true,"message" : "Login success."});
}
});
});

Die Chatseite der Anwendung lässt die Benutzer Nachrichten lesen und an andere Personen senden, die in der Anwendung eingeloggt sind. Da die Benutzer nur ihre eigenen Nachrichteninteraktionen mit anderen Nutzern sehen können, sind die vom Server zurückgesendeten Daten für die Chatseiten-Anfragen bei jedem Benutzer anders. Das Wichtigste: Der Zugriff auf diese Seite ist auf eingeloggten Benutzer beschränkt. Das Überprüfen des Sessions-Schlüssels offenbart, ob der Benutzer eingeloggt ist oder nicht:

app.get('/chat',function(req,res){
if(req.session.key) {
//user is already logged in,
//so let's render the chat page with the user email
res.render("chat.html",
{
app.get('/chat',function(req,res){
if(req.session.key) {
//Benutzer ist bereits eingeloggt// ,
// Rendern wir die Chatseite mit der Benutzer-E-Mail
res.render("chat.html",
{
email : req.session.key["UserEmail"],
name : req.session.key["UserName"]
});
} else {
// es konnte keine Session gefunden werden, gehen Sie zur Login-Seite
res.redirect("/");
}
});

Wenn der Benutzer einen neuen Kommentar von der Chatseite aus einreicht, sendet der Client JavaScript AJAX Formulardaten an den Server. Wenn der Benutzer eingeloggt ist, werden die Kommentare in die MySQL-UserComments-Tabelle eingefügt. Das geschieht durch Aufrufen der executeSendCommmentDbCommand – Funktion (wird hier nicht angezeigt).

app.post("/sendComment",function(req,res){
// This SQL command will insert a new comment in
// users table
if(req.session.key) {
executeSendCommmentDbCommand(req.body.Email, req.body.Recipient, req.body.Comment, function(dbResult){
if(!dbResult) {
res.json({"success" : true, "message" : "Comment has been sent successfully."});
} else {
res.json({"success" : false, "message" : "SendComment failed!"});
}
});
}app.post("/sendComment",function(req,res){
// Dieser SQL-Befehl fügt einen neuen Kommentar in
// die Benutzertabelle ein
if(req.session.key) {
executeSendCommmentDbCommand(req.body.Email, req.body.Recipient, req.body.Comment, function(dbResult){
if(!dbResult) {
res.json({"success" : true, "message" : "Der Kommentar wurde erfolgreich versendet."});
} else {
res.json({"success" : false, "message" : "SendComment ist fehlgeschlagen!"});
}
});
} else {
res.json({"success" : false, "message" : "Bitte zuerst einloggen."});
}
});

Wenn der Benutzer ausgeloggt ist, wird das Sessions-Objekt zerstört und der Benutzer wird auf die Login-Seite weitergeleitet. Aber zuerst speichert der executePersistSessionDbCommand (wird hier nicht angezeigt) die In-Memory-Benutzersession in der MySQL-Datenbank:

app.get('/logout',function(req,res){
// Benutzer ist eingeloggt, also zerstören wir die Session
// und leiten wir auf die Login-Seite weiter.
if(req.session.key) {
executePersistSessionDbCommand(req.session, function(dbResult){
if(!dbResult) {
req.session.destroy(function(){
res.redirect('/');
} else {
res.json({"success" : false, "message" : "Session persistence failed!"});
}
});
});
} else {
res.redirect('/');
}
});

Das ist nur ein sehr groben Überblick darüber, wie eine tatsächliche Anwendung von Redis als Session-Speicher aussieht. Aber es zeigt, wie Redis den In-Memor-Session-Status-Lebenszyklus in Kombination mit dem permanenten Datenbankspeicher wie MySQL verwalten kann.


Nächste Schritte