Comment accélérer la gestion de sessions d'application Python/MySQL avec Redis sur Ubuntu 22.04
L'auteur a choisi la Fondation Apache pour recevoir un don dans le cadre du programme Write for DOnations.
Introduction
L'authentification est le processus de vérification de l'identité des utilisateurs lors des demandes de connexion. Dans un processus d'authentification, les utilisateurs soumettent leurs identifiants sous forme de noms d'utilisateur et de mots de passe. Ensuite, l'application compare ces identifiants de connexion avec les entrées stockées dans la base de données. L'application accorde aux utilisateurs l'accès au système s'il y a correspondance.
Stocker des identifiants de connexion dans une base de données relationnelle comme MySQL ou PostgreSQL sans mécanisme de mise en cache est encore une approche courante et pratique, mais elle présente les limitations suivantes :
Surcharge de la base de données. L'application doit effectuer un aller-retour vers le serveur de base de données pour vérifier les identifiants des utilisateurs à partir d'une table de base de données chaque fois qu'un utilisateur soumet une demande de connexion. Comme la base de données peut encore servir d'autres requêtes de lecture/écriture, l'ensemble du processus surcharge la base de données et la rend lente.
Les bases de données traditionnelles sur disque ont des problèmes d'évolutivité. Lorsque votre application reçoit des milliers de demandes par seconde, les bases de données sur disque ne fonctionnent pas de manière optimale.
Pour surmonter les défis ci-dessus, vous pouvez utiliser Redis pour mettre en cache les identifiants de connexion des utilisateurs afin que votre application n'ait pas à contacter la base de données back-end à chaque demande de connexion. Redis est l'un des magasins de données ultrarapides les plus populaires qui utilise la RAM de votre ordinateur pour stocker des données sous forme de paires clé-valeur. Dans ce guide, vous utiliserez la base de données Redis pour accélérer la gestion des sessions dans votre application Python/MySQL sur le serveur Ubuntu 22.04.
Conditions préalables
Avant de commencer ce tutoriel, vous devrez configurer ce qui suit :
Déployer un serveur Ubuntu 22.04.
Configurer et initialiser le serveur.
Créer un utilisateur
sudonon root.Passez au nouveau compte d'utilisateur
sudoet installez :Serveur MySQL.
Serveur Redis.
Étape 1 — Installation des pilotes de base de données Python pour Redis et MySQL
Cette application stocke de manière permanente les identifiants des utilisateurs, tels que les noms et mots de passe, dans un serveur de base de données MySQL. Lorsqu'un utilisateur se connecte à l'application, un script Python interroge la base de données MySQL et compare les détails avec les valeurs stockées. Ensuite, le script Python met en cache les identifiants de connexion de l'utilisateur dans une base de données Redis pour traiter d'autres requêtes futures. Pour compléter cette logique, vos scripts Python nécessitent des pilotes de base de données (modules Python) pour communiquer avec les serveurs MySQL et Redis. Suivez les étapes ci-dessous pour installer les pilotes :
- Mettez à jour votre index d'informations sur les paquets et exécutez la commande suivante pour installer
python3-pip, un gestionnaire de paquets Python vous permettant d'installer des modules supplémentaires qui ne font pas partie de la bibliothèque standard de Python.
sudo apt install python3-pip
- Installez le pilote MySQL pour Python :
pip install mysql-connector-python
- Installez le pilote Redis pour Python :
pip install redis
Après avoir installé les pilotes nécessaires pour communiquer avec MySQL et Redis, passez à l'étape suivante et initialisez une base de données MySQL.
Étape 2 — Configuration d'une base de données MySQL échantillon
Pour ce guide, vous avez besoin d'une table MySQL. Dans un environnement de production, vous pouvez avoir des dizaines de tables qui servent d'autres requêtes. Configurez une base de données et créez la table en exécutant les commandes suivantes :
Connectez-vous au serveur de base de données MySQL en tant qu'utilisateur
root:sudo mysql -u root -pEntrez le mot de passe
rootde votre serveur MySQL lorsque cela vous sera demandé et appuyez surENTRERpour continuer. Ensuite, exécutez la commande suivante pour créer une base de donnéescompanyd'exemple et un comptecompany_user. Remplacezexample-mysql-passwordpar un mot de passe fort:
- 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;
Assurez-vous de recevoir la sortie suivante pour confirmer que les commandes précédentes ont été exécutées avec succès :
Query OK, 1 row affected (0.01 sec)Passez à la nouvelle base de données
entreprise:Confirmez que vous êtes connecté à la nouvelle base de données en vérifiant la sortie suivante :
Database changedCréez une table
system_users. La colonneuser_idsert dePRIMARY KEYpour identifier de manière unique chaque utilisateur. Les colonnesusernameetpasswordcontiennent les identifiants de connexion que les utilisateurs doivent soumettre pour se connecter à l'application. Les colonnesfirst_nameetlast_namestockent les noms des utilisateurs :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;Assurez-vous d'avoir créé la nouvelle table en vérifiant la sortie suivante :
Query OK, 0 rows affected (0.03 sec)Remplissez la table
system_usersavec des données d'exemple. Utilisez la fonction intégréeMD5(...)de MySQL pour hacher le mot de passe à des fins de sécurité :- 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'));
Vérifiez la sortie ci-dessous :
Query OK, 1 row affected (0.00 sec)Interrogez la table
system_userspour vous assurer que les données sont en place :- SELECT
- user_id,
- first_name,
- last_name,
- password
- FROM system_users;
Vérifiez la sortie suivante :
Déconnexion de la base de données MySQL :
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;
Vous avez maintenant configuré la bonne base de données MySQL pour votre application. Dans l'étape suivante, vous allez créer un module Python communiquant avec votre base de données d'exemple.
Étape 3 — Création d'un module de passerelle MySQL central pour Python
Lors de la codification de tout projet Python, vous devriez créer un module séparé pour chaque tâche afin de promouvoir la réutilisation du code. Dans cette étape, vous allez configurer un module central qui vous permettra de vous connecter et d'interroger la base de données MySQL depuis un script Python. Suivez les étapes ci-dessous :
Créez un répertoire
project. Ce répertoire sépare vos fichiers de code source Python des autres fichiers système:- mkdir project
Passez au nouveau
répertoirede projet :- cd project
Utilisez l'éditeur de texte
nanopour ouvrir un nouveau fichiermysql_db.py. Ce fichier héberge le module Python qui communique avec la base de données MySQL :Entrez les informations suivantes dans le fichier
mysql_db.py. Remplacezexample-mysql-passwordpar le mot de passe MySQL correct pour le comptecompany_user:Enregistrez et fermez le fichier
mysql_db.py.
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]
Le fichier du module mysql_db.py contient une classe (MysqlDb:) avec deux méthodes : - db_con(self):, qui se connecte à la base de données company d'exemple que vous avez créée plus tôt et renvoie une connexion MySQL réutilisable en utilisant l'instruction return mysql_con. - query(self, username, password):, une méthode qui accepte un username et un password et interroge la table system_users pour vérifier s'il y a une correspondance. L'instruction conditionnelle if row_count < 1: ... else: return result[1] renvoie la valeur booléenne False si un utilisateur n'existe pas dans la table ou le mot de passe de l'utilisateur (result[1]) si l'application trouve une correspondance.
Avec le module MySQL prêt, passez à l'étape suivante pour configurer un module Redis similaire qui communique avec le magasin de clés-valeurs Redis.
Étape 4 — Création d'un module Redis central pour Python
Dans cette étape, vous allez coder un module qui se connecte au serveur Redis. Exécutez les étapes suivantes :
Ouvrez un nouveau fichier
redis_db.py:Entrez les informations suivantes dans le fichier
redis_db.py. Remplacezexample-redis-passwordpar le mot de passe correct pour le serveur Redis :Enregistrez et fermez le fichier
redis_db.py.
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
Le fichier ci-dessus contient une classe (
RedisDb:).Dans cette classe, la méthode
db_con(self):utilise les identifiants fournis pour se connecter au serveur Redis et retourne une connexion réutilisable à l'aide de l'instructionreturn redis_con.
Après avoir configuré la classe Redis, créez le fichier principal de votre projet à l'étape suivante.
Étape 5 — Création du point d'entrée de l'application
Chaque application Python doit avoir un point d'entrée ou le fichier principal qui s'exécute lorsque l'application est lancée. Dans ce fichier, vous créerez un code qui affiche l'heure actuelle du serveur pour les utilisateurs authentifiés. Ce fichier utilise les modules MySQL et Redis personnalisés que vous avez créés pour authentifier les utilisateurs. Suivez les étapes ci-dessous pour créer le fichier :
Ouvrez un nouveau fichier
index.py:Entrez les informations suivantes dans le fichier
index.py:Enregistrez et fermez le fichier
index.py.
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.")
Dans le fichier
index.py, la sectionimport...ajoute les modules suivants à votre projet :utf_8,base64,md5etjson, modules de codage et de formatage de texte.
http.server,HTTPStatusetsocketserver, modules de serveur web.datetime, module de temps/date.mysql_dbetredis_db, des modules personnalisés que vous avez précédemment créés pour accéder aux serveurs MySQL et Redis.
La HttpHandler(http.server.SimpleHTTPRequestHandler): est une classe de gestionnaire pour le serveur HTTP. Sous cette classe, la méthode do_GET(self): traite les requêtes HTTP GET et affiche la date/heure du système pour les utilisateurs authentifiés.
Dans la logique if ... : else: ..., le script Python exécute l'instruction logique if redis_client.exists(auth_user): pour vérifier si les informations d'identification de l'utilisateur existent sur le serveur Redis. Si les détails de l'utilisateur existent et que le mot de passe stocké dans Redis ne correspond pas au mot de passe soumis par l'utilisateur, l'application renvoie l'erreur {"error": "Nom d'utilisateur/mot de passe invalide."}.
Si les détails de l'utilisateur n'existent pas sur le serveur Redis, l'application interroge le serveur de base de données MySQL en utilisant l'instruction mysql_resp =mysql_server.query(auth_user, auth_password). Si le mot de passe fourni par l'utilisateur ne correspond pas à la valeur stockée dans la base de données, l'application retourne l'erreur {"error": "Nom d'utilisateur/mot de passe invalide."}. Sinon, l'application met en cache les détails de l'utilisateur sur le serveur Redis en utilisant l'instruction redis_client.set(auth_user, mysql_resp).
Dans tous les cas où les identifiants de l'utilisateur correspondent aux détails de Redis/MySQL, l'application affiche la date/heure actuelle du système en utilisant la déclaration
{"time": current_time, ...}. L'entréeautorisée pardans la sortie vous permet de voir le serveur de base de données qui authentifie les utilisateurs dans l'application.
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)
Vous avez maintenant configuré le fichier principal de l'application. Dans l'étape suivante, vous allez tester l'application.
Étape 6 — Tester l'application
Dans cette étape, vous exécuterez votre application pour vérifier si le mécanisme de mise en cache Redis fonctionne. Exécutez les commandes ci-dessous pour tester l'application :
Utilisez la commande
python3suivante pour exécuter l'application :Assurez-vous que le serveur web personnalisé de l'application est en cours d'exécution :
Établissez une nouvelle connexion
SSHà votre serveur dans une nouvelle fenêtre de terminal et exécutez les commandescurlsuivantes pour envoyer quatre requêtes GET en utilisant les identifiants dejohn_doe's. Ajoutez[1-4]à la fin de l'URLhttp://localhost:8080/pour envoyer les quatre requêtes dans une seule commande:Vérifiez les sorties suivantes. Le serveur MySQL ne sert que la première demande d'authentification. Ensuite, la base de données Redis sert les trois demandes suivantes.
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"
}
Votre logique d'application fonctionne maintenant comme prévu.
Conclusion
Dans ce guide, vous avez construit une application Python qui utilise le serveur Redis pour mettre en cache les identifiants de connexion des utilisateurs. Redis est un serveur de base de données hautement disponible et scalable qui peut effectuer des milliers de transactions par seconde. Avec le mécanisme de mise en cache Redis dans votre application, vous pouvez réduire fortement le trafic sur votre serveur de base de données backend. Pour en savoir plus sur les applications Redis, consultez nos tutoriels Redis.
