Wie man die Sitzungsverwaltung von Python/MySQL-Anwendungen mit Redis auf Ubuntu 22.04 beschleunigt
Der Autor wählte die Apache Software Foundation, um eine Spende im Rahmen des Write for DOnations-Programms zu erhalten.
Einführung
Die Authentifizierung ist der Prozess der Überprüfung der Identität von Benutzern während Anmeldeanfragen. In einem Authentifizierungsprozess reichen die Benutzer ihre Anmeldeinformationen in Form von Benutzernamen und Passwörtern ein. Dann vergleicht die Anwendung diese Anmeldeinformationen mit gespeicherten Datenbankeinträgen. Die Anwendung gewährt den Benutzern Zugang zum System, wenn eine Übereinstimmung vorliegt.
Das Speichern von Anmeldeinformationen in einer relationalen Datenbank wie MySQL oder PostgreSQL ohne einen Caching-Mechanismus ist nach wie vor ein gängiger und praktischer Ansatz, bringt jedoch die folgenden Einschränkungen mit sich:
Überlastung der Datenbank. Die Anwendung muss jedes Mal, wenn ein Benutzer eine Anmeldeanfrage sendet, eine Verbindung zum Datenbankserver herstellen, um die Anmeldeinformationen der Benutzer aus einer Datenbanktabelle zu überprüfen. Da die Datenbank möglicherweise auch andere Lese-/Schreibanforderungen bearbeitet, überlastet der gesamte Prozess die Datenbank und macht sie langsamer.
-
Traditionelle, datenträgerbasierte Datenbanken haben Skalierungsprobleme. Wenn Ihre Anwendung Tausende von Anfragen pro Sekunde erhält, arbeiten datenträgerbasierte Datenbanken nicht optimal.
Um die oben genannten Herausforderungen zu überwinden, können Sie Redis verwenden, um die Anmeldedaten der Benutzer zwischenzuspeichern, sodass Ihre Anwendung nicht bei jeder Anmeldeforderung mit der Backend-Datenbank kommunizieren muss. Redis ist eines der beliebtesten ultran schnellen Datenspeicher, das den RAM Ihres Computers nutzt, um Daten in Schlüssel-Wert-Paaren zu speichern. In diesem Handbuch werden Sie die Redis-Datenbank verwenden, um die Sitzungsverwaltung in Ihrer Python/MySQL-Anwendung auf dem Ubuntu 22.04-Server zu beschleunigen.
Voraussetzungen
Bevor Sie mit diesem Tutorial beginnen, müssen Sie Folgendes einrichten:
Ein Ubuntu 22.04-Server bereitstellen.
Konfigurieren und initialisieren Sie den Server.
Einen Nicht-Root
sudoBenutzer erstellen.Wechseln Sie zum neuen
sudoBenutzerkonto und installieren Sie:MeinSQL-Server.
Redis-Server.
Schritt 1 — Installation der Python-Datenbanktreiber für Redis und MySQL
Diese Anwendung speichert die Anmeldedaten der Benutzer, wie Namen und Passwörter, dauerhaft in einem MySQL-Datenbankserver. Wenn sich ein Benutzer in der Anwendung anmeldet, fragt ein Python-Skript die MySQL-Datenbank ab und vergleicht die Details mit den gespeicherten Werten. Dann cached das Python-Skript die Anmeldedaten des Benutzers in einer Redis-Datenbank, um andere zukünftige Anfragen zu bedienen. Um diese Logik abzuschließen, benötigen Ihre Python-Skripte Datenbanktreiber (Python-Module), um mit den MySQL- und Redis-Servern zu kommunizieren. Befolgen Sie die folgenden Schritte, um die Treiber zu installieren:
- Aktualisieren Sie Ihr Paketinformations-Index und führen Sie den folgenden Befehl aus, um
python3-pipzu installieren, einen Python-Paketmanager, mit dem Sie zusätzliche Module installieren können, die nicht Teil der Python-Standardbibliothek sind.
sudo apt install python3-pip
- Installieren Sie den MySQL-Treiber für Python:
pip install mysql-connector-python
- Installieren Sie den Redis-Treiber für Python:
pip install redis
Nachdem Sie die erforderlichen Treiber zur Kommunikation mit MySQL und Redis installiert haben, fahren Sie mit dem nächsten Schritt fort und initialisieren Sie eine MySQL-Datenbank.
Schritt 2 — Einrichten einer Beispiel-MySQL-Datenbank
Für diesen Leitfaden benötigen Sie eine MySQL-Tabelle. In einer Produktionsumgebung können Sie Dutzende von Tabellen haben, die anderen Anforderungen dienen. Richten Sie eine Datenbank ein und erstellen Sie die Tabelle, indem Sie die folgenden Befehle ausführen:
Melden Sie sich als
rootBenutzer am MySQL-Datenbankserver an:sudo mysql -u root -pGeben Sie das
rootPasswort Ihres MySQL-Servers ein, wenn Sie dazu aufgefordert werden, und drücken SieENTER, um fortzufahren. Führen Sie dann den folgenden Befehl aus, um eine Beispiel-companyDatenbank und eincompany_userKonto zu erstellen. Ersetzen Sieexample-mysql-passworddurch ein sicheres Passwort:
- CREATE DATABASE company;
- CREATE USER 'company_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'example-mysql-password';
- GRANT ALL PRIVILEGES ON company.* TO 'company_user'@'localhost';
- FLUSH PRIVILEGES;
Stellen Sie sicher, dass Sie folgende Ausgabe erhalten, um zu bestätigen, dass die vorherigen Befehle erfolgreich ausgeführt wurden:
Query OK, 1 row affected (0.01 sec)Wechseln Sie zur neuen
companyDatenbank:Bestätigen Sie, dass Sie mit der neuen Datenbank verbunden sind, indem Sie die folgende Ausgabe überprüfen:
Database changedErstellen Sie eine
system_usersTabelle. Dieuser_idSpalte dient alsPRIMARY KEY, um jeden Benutzer eindeutig zu identifizieren. Die Spaltenusernameundpasswordsind die Anmeldedaten, die Benutzer eingeben müssen, um sich in der Anwendung anzumelden. Die Spaltenfirst_nameundlast_namespeichern die Namen der Benutzer:custom_prefix(mysql>) CREATE TABLE system_users ( user_id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50), first_name VARCHAR(50), last_name VARCHAR(50), password VARCHAR(50) ) ENGINE = InnoDB;Stellen Sie sicher, dass Sie die neue Tabelle erstellt haben, indem Sie die folgende Ausgabe überprüfen:
Query OK, 0 rows affected (0.03 sec)Füllen Sie die
system_usersTabelle mit Beispieldaten. Verwenden Sie die integrierte MySQL-FunktionMD5(...), um das Passwort aus Sicherheitsgründen zu hashen:- INSERT INTO system_users (username, first_name, last_name, password) VALUES ('john_doe', 'JOHN', 'DOE', MD5('password_1'));
- INSERT INTO system_users (username, first_name, last_name, password) VALUES ('mary_henry', 'MARY', 'HENRY', MD5('password_2'));
- INSERT INTO system_users (username, first_name, last_name, password) VALUES ('peter_jade', 'PETER', 'JADE', MD5('password_3'));
-
Überprüfen Sie die untenstehende Ausgabe:
Query OK, 1 row affected (0.00 sec) Abfragen Sie die Tabelle
system_users, um sicherzustellen, dass die Daten vorhanden sind:- SELECT
- user_id,
- first_name,
- last_name,
- password
- FROM system_users;
Überprüfen Sie die folgende Ausgabe:
Von der MySQL-Datenbank abmelden:
USE company;
+---------+------------+-----------+----------------------------------+
| user_id | first_name | last_name | password |
+---------+------------+-----------+----------------------------------+
| 1 | JOHN | DOE | 57210b12af5e06ad2e6e54a93b1465aa |
| 2 | MARY | HENRY | 259640f97ac2b4379dd540ff4016654c |
| 3 | PETER | JADE | 48ef85c894a06a4562268de8e4d934e1 |
+---------+------------+-----------+----------------------------------+
3 rows in set (0.00 sec)
- QUIT;
Sie haben jetzt die richtige MySQL-Datenbank für Ihre Anwendung eingerichtet. Im nächsten Schritt werden Sie ein Python-Modul erstellen, das mit Ihrer Musterdatenbank kommuniziert.
Schritt 3 — Erstellen eines zentralen MySQL-Gateway-Moduls für Python
Beim Programmieren eines Python-Projekts sollten Sie ein separates Modul für jede Aufgabe erstellen, um die Wiederverwendbarkeit des Codes zu fördern. In diesem Schritt richten Sie ein zentrales Modul ein, das es Ihnen ermöglicht, die MySQL-Datenbank von einem Python-Skript aus zu verbinden und abzufragen. Befolgen Sie die folgenden Schritte:
Erstellen Sie ein
project-Verzeichnis. Dieses Verzeichnis trennt Ihre Python-Quellcodedateien von den restlichen Systemdateien:- mkdir project
Wechseln Sie zum neuen
projectVerzeichnis:- cd project
Verwenden Sie den
nanoTexteditor, um eine neuemysql_db.pyDatei zu öffnen. Diese Datei enthält das Python-Modul, das mit der MySQL-Datenbank kommuniziert:Geben Sie die folgenden Informationen in die
mysql_db.pyDatei ein. Ersetzen Sieexample-mysql-passworddurch das korrekte MySQL-Passwort für dascompany_userKonto:Speichern Sie die
mysql_db.pyDatei und schließen Sie sie.
nano mysql_db.py
import mysql.connector
class MysqlDb:
def db_con(self):
mysql_con = mysql.connector.connect(
host = "localhost",
user = "company_user",
password = "example-mysql-password",
database = "company",
port = "3306"
)
return mysql_con
def query(self, username, password):
db = self.db_con()
db_cursor = db.cursor()
db_query = "select username, password from system_users where username = %s and password = md5(%s)"
db_cursor.execute(db_query, (username, password))
result = db_cursor.fetchone()
row_count = db_cursor.rowcount
if row_count < 1:
return False
else:
return result[1]
Die mysql_db.py Modul-Datei enthält eine Klasse (MysqlDb:) mit zwei Methoden: - db_con(self):, verbindet sich mit der Beispiel-Datenbank company, die Sie zuvor erstellt haben, und gibt eine wiederverwendbare MySQL-Verbindung mit der Anweisung return mysql_con zurück. - query(self, username, password):, eine Methode, die einen Benutzernamen und ein Passwort akzeptiert und die Tabelle system_users abfragt, um festzustellen, ob eine Übereinstimmung vorliegt. Die bedingte Anweisung if row_count < 1: ... else: return result[1] gibt den booleschen Wert False zurück, wenn ein Benutzer nicht in der Tabelle existiert oder das Passwort des Benutzers (result[1]), wenn die Anwendung eine Übereinstimmung findet.
Mit dem MySQL-Modul bereit, gehen Sie zum nächsten Schritt über, um ein ähnliches Redis-Modul einzurichten, das mit dem Redis-Key-Value-Store kommuniziert.
Schritt 4 — Erstellung eines zentralen Redis-Moduls für Python
In diesem Schritt werden Sie ein Modul programmieren, das sich mit dem Redis-Server verbindet. Führen Sie die folgenden Schritte aus:
Öffne eine neue
redis_db.pyDatei:Geben Sie die folgenden Informationen in die
redis_db.py-Datei ein. Ersetzen Sieexample-redis-passworddurch das korrekte Passwort für den Redis-Server:Speichern Sie die
redis_db.pyDatei und schließen Sie sie.
nano redis_db.py
import redis
class RedisDb:
def db_con(self):
r_host = 'localhost'
r_port = 6379
r_pass = 'example-redis-password'
redis_con = redis.Redis(host = r_host, port = r_port, password = r_pass)
return redis_con
Die obige Datei hat eine Klasse (
RedisDb:).In dieser Klasse verwendet die
db_con(self):-Methode die bereitgestellten Anmeldeinformationen, um eine Verbindung zum Redis-Server herzustellen und gibt eine wiederverwendbare Verbindung mit derreturn redis_con-Anweisung zurück.
Nachdem Sie die Redis-Klasse eingerichtet haben, erstellen Sie im nächsten Schritt die Hauptdatei für Ihr Projekt.
Schritt 5 — Erstellen des Einstiegspunkts der Anwendung
Jede Python-Anwendung muss einen Einstiegspunkt oder eine Hauptdatei haben, die ausgeführt wird, wenn die Anwendung gestartet wird. In dieser Datei erstellen Sie einen Code, der die aktuelle Serverzeit für authentifizierte Benutzer anzeigt. Diese Datei verwendet die benutzerdefinierten MySQL- und Redis-Module, die Sie erstellt haben, um Benutzer zu authentifizieren. Folgen Sie den folgenden Schritten, um die Datei zu erstellen:
Öffnen Sie eine neue
index.pyDatei:Geben Sie die folgenden Informationen in die
index.pyDatei ein:Speichern Sie die
index.pyDatei und schließen Sie sie.
nano index.py
from encodings import utf_8
import base64
from hashlib import md5
import json
import datetime
import http.server
from http import HTTPStatus
import socketserver
import mysql_db
import redis_db
class HttpHandler(http.server.SimpleHTTPRequestHandler):
def do_GET(self):
self.send_response(HTTPStatus.OK)
self.send_header('Content-type', 'application/json')
self.end_headers()
authHeader = self.headers.get('Authorization').split(' ');
auth_user, auth_password = base64.b64decode(authHeader[1]).decode('utf8').split(':')
mysql_server = mysql_db.MysqlDb()
redis_server = redis_db.RedisDb()
redis_client = redis_server.db_con()
now = datetime.datetime.now()
current_time = now.strftime("%Y-%m-%d %H:%M:%S")
resp = {}
if redis_client.exists(auth_user):
if md5(auth_password.encode('utf8')).hexdigest() != redis_client.get(auth_user).decode('utf8'):
resp = {"error": "Invalid username/password."}
else:
resp = {"time": current_time, "authorized by": "Redis server"}
else:
mysql_resp = mysql_server.query(auth_user, auth_password)
if mysql_resp == False:
resp = {"error": "Invalid username/password."}
else:
resp = {"time": current_time, "authorized by": "MySQL server"}
redis_client.set(auth_user, mysql_resp)
self.wfile.write(bytes(json.dumps(resp, indent = 2) + "\r\n", "utf8"))
httpd = socketserver.TCPServer(('', 8080), HttpHandler)
print("Web server is running on port 8080...")
try:
httpd.serve_forever()
except KeyboardInterrupt:
httpd.server_close()
print("Web server has stopped runing.")
In der
index.pyDatei fügt derimport...Abschnitt folgende Module zu Ihrem Projekt hinzu:utf_8,base64,md5undjson, Textkodierungs- und Formatierungs-Module.
http.server,HTTPStatusundsocketserver, Webserver-Module.datetime, Zeit-/Datumsmodul.mysql_dbundredis_db, benutzerdefinierte Module, die Sie zuvor erstellt haben, um auf die MySQL- und Redis-Server zuzugreifen.
Die HttpHandler(http.server.SimpleHTTPRequestHandler): ist eine Handler-Klasse für den HTTP-Server. In der Klasse bedient die Methode do_GET(self): die HTTP GET Anfragen und zeigt das Datum/Zeit des Systems für authentifizierte Benutzer an.
In der if ... : else: ... Logik führt das Python-Skript die logische if redis_client.exists(auth_user): Anweisung aus, um zu überprüfen, ob die Anmeldedaten des Benutzers auf dem Redis-Server vorhanden sind. Wenn die Benutzerdaten vorhanden sind und das im Redis gespeicherte Passwort nicht mit dem vom Benutzer eingegebenen Passwort übereinstimmt, gibt die Anwendung den Fehler {"error": "Ungültiger Benutzername/Passwort."} zurück.
Wenn die Benutzerdaten nicht im Redis-Server vorhanden sind, fragt die Anwendung den MySQL-Datenbankserver mit der Anweisung mysql_resp =mysql_server.query(auth_user, auth_password) ab. Falls das vom Benutzer angegebene Passwort nicht mit dem im Datenbank gespeicherten Wert übereinstimmt, gibt die Anwendung den Fehler {"error": "Ungültiger Benutzername/Passwort."} zurück. Andernfalls speichert die Anwendung die Benutzerdaten im Redis-Server mit der Anweisung redis_client.set(auth_user, mysql_resp).
In allen Fällen, in denen die Anmeldedaten des Benutzers mit den Redis/MySQL-Details übereinstimmen, zeigt die Anwendung das aktuelle Datum/Uhrzeit des Systems an, indem die Anweisung
{"time": current_time, ...}verwendet wird. Der Eintragauthorized byin der Ausgabe ermöglicht es Ihnen, den Datenbankserver zu sehen, der die Benutzer in der Anwendung authentifiziert.
if redis_client.exists(auth_user):
if md5(auth_password.encode('utf8')).hexdigest() != redis_client.get(auth_user).decode('utf8'):
resp = {"error": "Invalid username/password."}
else:
resp = {"time": current_time, "authorized by": "Redis server"}
else:
mysql_resp = mysql_server.query(auth_user, auth_password)
if mysql_resp == False:
resp = {"error": "Invalid username/password."}
else:
resp = {"time": current_time, "authorized by": "MySQL server"}
redis_client.set(auth_user, mysql_resp)
Sie haben nun die Hauptdatei für die Anwendung eingerichtet. Im nächsten Schritt werden Sie die Anwendung testen.
Schritt 6 — Testen der Anwendung
In diesem Schritt werden Sie Ihre Anwendung ausführen, um zu sehen, ob der Redis-Caching-Mechanismus funktioniert. Führen Sie die folgenden Befehle aus, um die Anwendung zu testen:
Verwenden Sie den folgenden
python3Befehl, um die Anwendung auszuführen:Stellen Sie sicher, dass der benutzerdefinierte Webserver der Anwendung läuft:
Stellen Sie eine weitere
SSH-Verbindung zu Ihrem Server in einem neuen Terminalfenster her und führen Sie die folgendencurl-Befehle aus, um vier GET-Anfragen mit den Anmeldeinformationen vonjohn_doe'szu senden. Fügen Sie[1-4]am Ende derhttp://localhost:8080/-URL hinzu, um die vier Anfragen in einem einzigen Befehl zu senden:Überprüfen Sie die folgenden Ausgaben. Der MySQL-Server bearbeitet nur die erste Authentifizierungsanfrage. Danach bearbeitet die Redis-Datenbank die nächsten drei Anfragen.
python3 index.py
Web server is running on port 8080...
curl -X GET -u john_doe:password_1 http://localhost:8080/[1-4]
[1/4]
{
"time": "2023-11-07 10:04:38",
"authorized by": "MySQL server"
}
[4/4]
{
"time": "2023-11-07 10:04:38",
"authorized by": "Redis server"
}
Ihre Anwendungslogik funktioniert jetzt wie erwartet.
Schlussfolgerung
In diesem Leitfaden haben Sie eine Python-Anwendung erstellt, die den Redis-Server verwendet, um die Anmeldedaten der Benutzer zwischenzuspeichern. Redis ist ein hochverfügbarer und skalierbarer Datenbankserver, der Tausende von Transaktionen pro Sekunde durchführen kann. Mit dem Redis-Caching-Mechanismus in Ihrer Anwendung können Sie den Datenverkehr in Ihrem Backend-Datenbankserver erheblich reduzieren. Um mehr über Redis-Anwendungen zu erfahren, konsultieren Sie unsere Redis-Tutorials.
