So beschleunigen Sie die Sitzungsverwaltung von Python/MySQL-Anwendungen mit Redis auf Ubuntu 22.04

Einführung

Authentifizierung ist der Prozess der Überprüfung der Identität von Benutzern bei Login-Anfragen. Bei einem Authentifizierungsprozess geben Benutzer ihre Anmeldeinformationen als Benutzernamen und Passwörter ein. Anschließend gleicht die Anwendung diese Anmeldeinformationen mit gespeicherten Datenbankeinträgen ab. Wenn es eine Übereinstimmung gibt, gewährt die Anwendung den Benutzern Zugriff auf das System.

Das Speichern von Anmeldeinformationen in einer relationalen Datenbank wie MySQL oder PostgreSQL ohne Zwischenspeicherungsmechanismus ist immer noch ein gängiger und praktischer Ansatz, birgt jedoch folgende Einschränkungen:

  • Überlastung der Datenbank. Die Anwendung muss bei jeder Login-Anfrage eines Benutzers einen Hin- und Rückweg zum Datenbankserver machen, um die Anmeldeinformationen aus einer Datenbanktabelle zu überprüfen. Da die Datenbank möglicherweise immer noch andere Lese-/Schreibzugriffsanfragen bedient, überlastet der gesamte Prozess die Datenbank und macht ihn langsam.

  • Traditionelle datenträgerbasierte Datenbanken haben Skalierbarkeitsprobleme. Wenn Ihre Anwendung Tausende von Anfragen pro Sekunde erhält, funktionieren datenträgerbasierte Datenbanken nicht optimal.

Um die oben genannten Herausforderungen zu bewältigen, können Sie Redis verwenden, um die Anmeldeinformationen der Benutzer im Cache zu speichern, damit Ihre Anwendung nicht bei jeder Anmeldeanforderung auf die Backend-Datenbank zugreifen muss. Redis ist einer der beliebtesten ultraschnellen Datenspeicher, der den RAM Ihres Computers verwendet, um Daten in Schlüssel-Wert-Paaren zu speichern. In diesem Leitfaden verwenden Sie die Redis-Datenbank, 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:

Schritt 1 — Installation der Python-Datenbanktreiber für Redis und MySQL

Diese Anwendung speichert die Anmeldeinformationen der Benutzer, wie Namen und Passwörter, dauerhaft in einer MySQL-Datenbank. Beim Einloggen eines Benutzers ruft ein Python-Skript die MySQL-Datenbank ab und gleicht die Details mit den gespeicherten Werten ab. Anschließend speichert das Python-Skript die Anmeldeinformationen des Benutzers in einer Redis-Datenbank ab, um zukünftige Anfragen zu bedienen. Um diese Logik abzuschließen, benötigen Ihre Python-Skripte Treiber (Python-Module), um mit den MySQL- und Redis-Servern zu kommunizieren. Befolgen Sie die folgenden Schritte, um die Treiber zu installieren:

  1. Aktualisieren Sie Ihren Paketinformationsindex und führen Sie den folgenden Befehl aus, um python3-pip zu 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
  1. Installieren Sie den MySQL-Treiber für Python:
pip install mysql-connector-python
  1. Installieren Sie den Redis-Treiber für Python:
pip install redis

Nachdem Sie die erforderlichen Treiber für die 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

In diesem Leitfaden benötigen Sie eine MySQL-Tabelle. In einer Produktionsumgebung können Sie Dutzende von Tabellen haben, die andere Anfragen bedienen. Richten Sie eine Datenbank ein und erstellen Sie die Tabelle, indem Sie die folgenden Befehle ausführen:

  1. Melden Sie sich als Benutzer root beim MySQL-Datenbankserver an:

    sudo mysql -u root -p
    
  2. Geben Sie das root-Passwort Ihres MySQL-Servers ein, wenn Sie dazu aufgefordert werden, und drücken Sie ENTER, um fortzufahren. Führen Sie dann den folgenden Befehl aus, um eine Beispieldatenbank company und einen Benutzer company_user zu erstellen. Ersetzen Sie example-mysql-password durch ein starkes Passwort:

  1. CREATE DATABASE company;
  2. CREATE USER 'company_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'example-mysql-password';
  3. GRANT ALL PRIVILEGES ON company.* TO 'company_user'@'localhost';
  4. FLUSH PRIVILEGES;
  1. Stellen Sie sicher, dass Sie die folgende Ausgabe erhalten, um zu bestätigen, dass die vorherigen Befehle erfolgreich ausgeführt wurden:

    Ausgabe
    Query OK, 1 Zeile betroffen (0.01 Sek)
  2. Wechseln Sie zur neuen company Datenbank:

    1. USE company;
  3. Bestätigen Sie, dass Sie mit der neuen Datenbank verbunden sind, indem Sie die folgende Ausgabe überprüfen:

    Ausgabe
    Datenbank geändert
  4. Erstellen Sie eine Tabelle system_users. Die Spalte user_id dient als PRIMARY KEY, um jeden Benutzer eindeutig zu identifizieren. Die Spalten username und password sind die Anmeldeinformationen, die Benutzer eingeben müssen, um sich in der Anwendung anzumelden. Die Spalten first_name und last_name speichern 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;
    
  5. Stellen Sie sicher, dass Sie die neue Tabelle erstellt haben, indem Sie die folgende Ausgabe überprüfen:

    Ausgabe
    Query OK, 0 rows affected (0.03 sec)
  6. Füllen Sie die Tabelle system_users mit Beispieldaten. Verwenden Sie die integrierte MySQL-Funktion MD5(...), um das Passwort aus Sicherheitsgründen zu hashen:

    1. INSERT INTO system_users (username, first_name, last_name, password) VALUES ('john_doe', 'JOHN', 'DOE', MD5('password_1'));
    2. INSERT INTO system_users (username, first_name, last_name, password) VALUES ('mary_henry', 'MARY', 'HENRY', MD5('password_2'));
    3. INSERT INTO system_users (username, first_name, last_name, password) VALUES ('peter_jade', 'PETER', 'JADE', MD5('password_3'));
  7. Überprüfen Sie die Ausgabe unten:

    Ausgabe
    Query OK, 1 Zeile betroffen (0.00 Sekunden)
  8. Abfragen Sie die Tabelle „system_users“, um sicherzustellen, dass die Daten vorhanden sind:

    1. SELECT
    2. user_id,
    3. first_name,
    4. last_name,
    5. password
    6. FROM system_users;
  9. Überprüfen Sie die folgende Ausgabe:

    Ausgabe
    +---------+------------+-----------+----------------------------------+ | user_id | first_name | last_name | password | +---------+------------+-----------+----------------------------------+ | 1 | JOHN | DOE | 57210b12af5e06ad2e6e54a93b1465aa | | 2 | MARY | HENRY | 259640f97ac2b4379dd540ff4016654c | | 3 | PETER | JADE | 48ef85c894a06a4562268de8e4d934e1 | +---------+------------+-----------+----------------------------------+ 3 Zeilen in Set (0.00 sec)
  10. Melden Sie sich von der MySQL-Datenbank ab:

    1. QUIT;

Sie haben nun die richtige MySQL-Datenbank für Ihre Anwendung eingerichtet. Im nächsten Schritt werden Sie ein Python-Modul erstellen, das mit Ihrer Beispieldatenbank kommuniziert.

Schritt 3 – Erstellen eines zentralen MySQL-Gateway-Moduls für Python

Bei der Programmierung eines Python-Projekts sollten Sie für jede Aufgabe ein separates Modul erstellen, um die Wiederverwendbarkeit des Codes zu fördern. In diesem Schritt richten Sie ein zentrales Modul ein, das es Ihnen ermöglicht, sich von einem Python-Skript aus mit der MySQL-Datenbank zu verbinden und Abfragen durchzuführen. Befolgen Sie die folgenden Schritte:

  1. Erstellen Sie ein Projekt-Verzeichnis. Dieses Verzeichnis trennt Ihre Python-Quellcode-Dateien von den restlichen Systemdateien:

    1. mkdir project
  2. Wechseln Sie zum neuen Projekt -Verzeichnis:

    1. cd Projekt
  3. Verwenden Sie den Texteditor nano, um eine neue Datei mysql_db.py zu öffnen. Diese Datei enthält das Python-Modul, das mit der MySQL-Datenbank kommuniziert:

    nano mysql_db.py
    
  4. Geben Sie die folgenden Informationen in die Datei mysql_db.py ein. Ersetzen Sie example-mysql-password durch das korrekte MySQL-Passwort für das Konto company_user:

    ~/project/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]
    
  5. Speichern Sie die Datei mysql_db.py und schließen Sie sie.

Die Moduldatei mysql_db.py enthält eine Klasse (MysqlDb:) mit zwei Methoden:
db_con(self): stellt eine Verbindung zur zuvor erstellten Beispiel-Datenbank company her und gibt eine wiederverwendbare MySQL-Verbindung mit der Anweisung return mysql_con zurück.
query(self, username, password): eine Methode, die einen username und password akzeptiert und die Tabelle system_users abfragt, um festzustellen, ob es eine Übereinstimmung gibt. 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 fertigen MySQL-Modul folgen Sie dem nächsten Schritt, um ein ähnliches Redis-Modul einzurichten, das mit dem Redis-Key-Value-Store kommuniziert.

Schritt 4 — Erstellen eines zentralen Redis-Moduls für Python

In diesem Schritt codieren Sie ein Modul, das eine Verbindung zum Redis-Server herstellt. Führen Sie die folgenden Schritte aus:

  1. Öffnen Sie eine neue redis_db.py Datei:

    nano redis_db.py
    
  2. Geben Sie die folgenden Informationen in die Datei redis_db.py ein. Ersetzen Sie example-redis-password durch das richtige Passwort für den Redis-Server:

    ~/Projekt/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
    
  3. Speichern und schließen Sie die Datei redis_db.py.

  • Die oben genannte Datei enthält eine Klasse (RedisDb:).

  • Unter dieser Klasse verwendet die Methode db_con(self): die bereitgestellten Anmeldeinformationen, um eine Verbindung zum Redis-Server herzustellen, und gibt eine wiederverwendbare Verbindung mit der Anweisung return redis_con 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 die Hauptdatei haben, die beim Ausführen der Anwendung ausgeführt wird. In dieser Datei erstellen Sie einen Code, der die aktuelle Serverzeit für authentifizierte Benutzer anzeigt. Diese Datei verwendet die von Ihnen erstellten benutzerdefinierten MySQL- und Redis-Module zur Authentifizierung der Benutzer. Befolgen Sie die folgenden Schritte, um die Datei zu erstellen:

  1. Öffnen Sie eine neue index.py-Datei:

    nano index.py
    
  2. Geben Sie die folgenden Informationen in die Datei index.py ein:

    ~/projekt/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": "Ungültiger Benutzername/Passwort."}
                else:
                    resp = {"time": current_time, "authorisiert durch": "Redis Server"}
            else:
                mysql_resp  = mysql_server.query(auth_user, auth_password)
                if mysql_resp == False:
                     resp =  {"error": "Ungültiger Benutzername/Passwort."}
                else:
                    resp = {"time": current_time, "authorisiert durch": "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("Webserver läuft auf Port 8080...")
    
    try:
        httpd.serve_forever()
    except KeyboardInterrupt:
        httpd.server_close()
        print("Webserver wurde gestoppt.")
    
  3. Speichern und schließen Sie die Datei index.py.

  • In der Datei index.py fügt der Abschnitt import... die folgenden Module zu Ihrem Projekt hinzu:

    • utf_8, base64, md5 und json, Textkodierung und Formatierungsmodule.

    • http.server, HTTPStatus und socketserver, Webservermodule.

    • datetime, Zeit-/Datumsmodul.

    • mysql_db und redis_db, benutzerdefinierte Module, die Sie zuvor erstellt haben, um auf die MySQL- und Redis-Server zuzugreifen.

  • Der HttpHandler(http.server.SimpleHTTPRequestHandler): ist eine Handler-Klasse für den HTTP-Server. Unterhalb der Klasse dient die Methode do_GET(self): dazu, HTTP-GET-Anfragen zu bedienen und das Datum/Uhrzeit des Systems für authentifizierte Benutzer anzuzeigen.

  • In der if ... : else: ... Logik führt das Python-Skript die logische Anweisung if redis_client.exists(auth_user): aus, um zu überprüfen, ob die Anmeldeinformationen des Benutzers im Redis-Server vorhanden sind. Wenn die Benutzerdetails existieren und das gespeicherte Redis-Passwort nicht mit dem vom Benutzer eingegebenen Passwort übereinstimmt, gibt die Anwendung den Fehler {"error": "Ungültiger Benutzername/Passwort."} zurück.

Wenn die Benutzerdetails 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 eingegebene Passwort nicht mit dem in der Datenbank gespeicherten Wert übereinstimmt, gibt die Anwendung den Fehler {"error": "Ungültiger Benutzername/Passwort."} zurück. Andernfalls speichert die Anwendung die Benutzerdetails im Redis-Server mit der Anweisung redis_client.set(auth_user, mysql_resp).

  • In allen Fällen, in denen die Benutzerdaten mit den Redis/MySQL-Details übereinstimmen, zeigt die Anwendung das aktuelle Datum/Uhrzeit des Systems mit der Anweisung {"time": current_time, ...} an. Der Eintrag authorized by in 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": "Ungültiger Benutzername/-passwort."}
          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": "Ungültiger Benutzername/-passwort."}
          else:
              resp = {"time": current_time, "authorized by": "MySQL-Server"}
              redis_client.set(auth_user, mysql_resp)   
    

Sie haben jetzt 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:

  1. Verwenden Sie den folgenden python3-Befehl, um die Anwendung auszuführen:

    python3 index.py
    
  2. Stellen Sie sicher, dass der benutzerdefinierte Webserver der Anwendung ausgeführt wird:

    Ausgabe
    Webserver läuft auf Port 8080...
  3. Richten Sie eine neue SSH-Verbindung zu Ihrem Server in einem neuen Terminalfenster ein und führen Sie die folgenden curl-Befehle aus, um vier GET-Anfragen mit den Anmeldeinformationen von john_doe zu senden. Fügen Sie am Ende der URL http://localhost:8080/ [1-4] hinzu, um die vier Anfragen in einem einzigen Befehl zu senden:

    curl -X GET -u john_doe:password_1  http://localhost:8080/[1-4]
    
  4. Überprüfen Sie die folgenden Ausgaben. Der MySQL-Server bedient nur die erste Authentifizierungsanfrage. Dann bedient die Redis-Datenbank die nächsten drei Anfragen.

    Ausgabe
    [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 Anmeldeinformationen der Benutzer im Cache zu speichern. 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 auf Ihrem Backend-Datenbankserver erheblich reduzieren. Um mehr über Redis-Anwendungen zu erfahren, besuchen Sie unsere Redis-Tutorials.

Source:
https://www.digitalocean.com/community/tutorials/how-to-speed-up-python-mysql-application-session-handling-with-redis-on-ubuntu-22-04