Как ускорить обработку сеансов приложений Python/MySQL с помощью Redis в Ubuntu 22.04
Автор выбрал Apache Software Foundation для получения пожертвования в рамках программы Write for DOnations.
Введение
Аутентификация — это процесс проверки личности пользователей во время запросов на вход. В процессе аутентификации пользователи предоставляют свои учетные данные в виде имен пользователей и паролей. Затем приложение сопоставляет эти учетные данные для входа с сохраненными записями базы данных. Приложение предоставляет пользователям доступ к системе, если есть совпадение.
Хранение учетных данных для входа в реляционную базу данных, такую как MySQL или PostgreSQL, без механизма кэширования по-прежнему является распространенным и практичным подходом, но имеет следующие ограничения:
Перегрузка базы данных. Приложение должно совершать обратный путь к серверу базы данных для проверки учетных данных пользователей из таблицы базы данных каждый раз, когда пользователь отправляет запрос на вход. Поскольку база данных может по-прежнему обслуживать другие запросы на чтение/запись, весь процесс перегружает базу данных и замедляет ее работу.
Традиционные дисковые базы данных имеют проблемы с масштабируемостью. Когда ваше приложение получает тысячи запросов в секунду, дисковые базы данных работают не оптимально.
Чтобы преодолеть вышеуказанные проблемы, вы можете использовать Redis для кэширования учетных данных пользователей, чтобы вашему приложению не приходилось обращаться к внутренней базе данных во время каждого запроса на вход. Redis — одно из самых популярных сверхбыстрых хранилищ данных, которое использует оперативную память вашего компьютера для хранения данных в парах ключ-значение. В этом руководстве вы будете использовать базу данных Redis для ускорения обработки сеансов в вашем приложении Python/MySQL на сервере Ubuntu 22.04.
Предварительные условия
Прежде чем приступить к работе с этим руководством, вам необходимо настроить следующее:
Разверните сервер Ubuntu 22.04.
Настройте и инициализируйте сервер.
Создайте пользователя
sudo
без полномочий root.Переключитесь на новую учетную запись пользователя
sudo
и установите:MySQL-сервер.
Редис-сервер.
Шаг 1. Установка драйверов базы данных Python для Redis и MySQL
Это приложение постоянно хранит учетные данные пользователей, такие как имена и пароли, на сервере базы данных MySQL. Когда пользователь входит в приложение, сценарий Python запрашивает базу данных MySQL и сопоставляет данные с сохраненными значениями. Затем сценарий Python кэширует учетные данные пользователя для входа в базу данных Redis для обслуживания других будущих запросов. Для реализации этой логики вашим сценариям Python требуются драйверы базы данных (модули Python) для связи с серверами MySQL и Redis. Для установки драйверов выполните следующие действия:
- Обновите индекс информации о пакете и выполните следующую команду, чтобы установить
python3-pip
, менеджер пакетов Python, позволяющий устанавливать дополнительные модули, не входящие в стандартную библиотеку Python.
sudo apt install python3-pip
- Установите драйвер MySQL для Python:
pip install mysql-connector-python
- Установите драйвер Redis для Python:
pip install redis
После установки необходимых драйверов для связи с MySQL и Redis перейдите к следующему шагу и инициализируйте базу данных MySQL.
Шаг 2 — Настройка образца базы данных MySQL
Для этого руководства вам понадобится одна таблица MySQL. В производственной среде у вас могут быть десятки таблиц, которые обслуживают другие запросы. Настройте базу данных и создайте таблицу, выполнив следующие команды:
Войдите на сервер базы данных MySQL как пользователь
root
:sudo mysql -u root -p
При появлении запроса введите пароль
root
вашего сервера MySQL и нажмитеENTER
, чтобы продолжить. Затем выполните следующую команду, чтобы создать образец базы данныхcompany
и учетную записьcompany_user
. Заменитеexample-mysql-password
надежным паролем:
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;
Убедитесь, что вы получили следующий вывод, подтверждающий успешное выполнение предыдущих команд:
Query OK, 1 row affected (0.01 sec)
Переключитесь на новую базу данных
company
:
Подтвердите, что вы подключены к новой базе данных, проверив следующий вывод:
Database changed
Создайте таблицу system_users
. Столбец user_id
служит PRIMARY KEY
для уникальной идентификации каждого пользователя. Столбцы username
и password
— это учетные данные для входа, которые пользователи должны предоставить для входа в приложение. В столбцах first_name
и last_name
хранятся имена пользователей:
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;
Убедитесь, что вы создали новую таблицу, проверив следующий вывод:
Query OK, 0 rows affected (0.03 sec)
Заполните таблицу system_users
примерами данных. Используйте встроенную функцию MySQL MD5(...)
для хэширования пароля в целях безопасности:
Проверьте вывод ниже:
Query OK, 1 row affected (0.00 sec)
Запросите таблицу system_users
, чтобы убедиться, что данные на месте:
Проверьте следующий вывод:
+---------+------------+-----------+----------------------------------+| 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)
Выйдите из базы данных MySQL:
Теперь вы настроили подходящую базу данных MySQL для своего приложения. На следующем шаге вы создадите модуль Python, взаимодействующий с вашим примером базы данных.
Шаг 3 — Создание центрального модуля шлюза MySQL для Python
При кодировании любого проекта Python вам следует создать отдельный модуль для каждой задачи, чтобы обеспечить возможность повторного использования кода. На этом этапе вы настроите центральный модуль, который позволит вам подключаться и отправлять запросы к базе данных MySQL из сценария Python. Выполните следующие действия:
Создайте каталог
project
. Этот каталог отделяет файлы исходного кода Python от остальных системных файлов:
Перейдите в новый каталог project
:
Используйте текстовый редактор nano
, чтобы открыть новый файл mysql_db.py
. В этом файле находится модуль Python, который взаимодействует с базой данных MySQL:
nano mysql_db.py
Введите следующую информацию в файл mysql_db.py
. Замените example-mysql-password
правильным паролем MySQL для учетной записи company_user
:
import mysql.connectorclass 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_condef 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]
Сохраните и закройте файл mysql_db.py
.
Файл модуля mysql_db.py
содержит один класс (MysqlDb:
) с двумя методами: - db_con(self):
подключается к образцу базы данных company
, который вы создали ранее, и возвращает повторно используемое соединение MySQL с помощью оператора return mysql_con
. - query(self, username,password):
, метод, который принимает имя пользователя
и пароль
и запрашивает system_users
таблица, чтобы найти совпадение. Условный оператор if row_count < 1: ... else: return result[1]
возвращает логическое значение False
, если пользователь не существует в таблице или пользовательском списке. пароль (result[1]
), если приложение находит совпадение.
Когда модуль MySQL готов, выполните следующий шаг, чтобы настроить аналогичный модуль Redis, который будет обмениваться данными с хранилищем значений ключей Redis.
Шаг 4 — Создание центрального модуля Redis для Python
На этом этапе вы напишите модуль, который подключается к серверу Redis. Выполните следующие шаги:
Откройте новый файл
redis_db.py
:nano redis_db.py
Введите следующую информацию в файл
redis_db.py
. Заменитеexample-redis-password
правильным паролем для сервера Redis:import redisclass 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
Сохраните и закройте файл
redis_db.py
.
В приведенном выше файле есть один класс (
RedisDb:
).В этом классе метод
db_con(self):
использует предоставленные учетные данные для подключения к серверу Redis и возвращает повторно используемое соединение с помощью оператораreturn redis_con
.
После настройки класса Redis на следующем шаге создайте основной файл для вашего проекта.
Шаг 5 — Создание точки входа приложения
Каждое приложение Python должно иметь точку входа или основной файл, который выполняется при запуске приложения. В этом файле вы создадите код, который показывает время текущего сервера для аутентифицированных пользователей. Этот файл использует созданные вами пользовательские модули MySQL и Redis для аутентификации пользователей. Чтобы создать файл, выполните следующие действия:
Откройте новый файл
index.py
:nano index.py
Введите следующую информацию в файл
index.py
:from encodings import utf_8import base64from hashlib import md5import jsonimport datetimeimport http.serverfrom http import HTTPStatusimport socketserverimport mysql_dbimport redis_dbclass 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.")
Сохраните и закройте файл
index.py
.
В файле
index.py
разделimport...
добавляет в ваш проект следующие модули:utf_8
,base64
,md5
иjson
, модули кодирования и форматирования текста.
http.server
,HTTPStatus
иsocketserver
— модули веб-сервера.datetime
, модуль времени/даты.mysql_db
иredis_db
— пользовательские модули, которые вы ранее создали для доступа к серверам MySQL и Redis.
HttpHandler(http.server.SimpleHTTPRequestHandler):
— это класс-обработчик HTTP-сервера. В этом классе метод do_GET(self):
обслуживает HTTP-запросы GET и отображает системную дату/время для аутентифицированных пользователей.
В логике if ... : else: ...
скрипт Python запускает логический оператор if redis_client.exists(auth_user):
, чтобы проверить, существуют ли учетные данные пользователя. на сервере Redis. Если данные пользователя существуют и сохраненный пароль Redis не соответствует отправленному паролю пользователя, приложение возвращает ошибку {"error": "Invalid username/password."
.
Если данные пользователя отсутствуют на сервере Redis, приложение запрашивает сервер базы данных MySQL с помощью оператора mysql_resp=mysql_server.query(auth_user, auth_password)
. Если предоставленный пользователем пароль не соответствует значению, хранящемуся в базе данных, приложение возвращает ошибку {"error": "Invalid username/password."
. В противном случае приложение кэширует данные пользователя на сервере Redis с помощью оператора redis_client.set(auth_user, mysql_resp)
.
Во всех случаях, когда учетные данные пользователя соответствуют данным Redis/MySQL, приложение отображает текущую дату/время системы с помощью оператора
{"time": current_time, ...
. Записьauthorized by
в выходных данных позволяет вам увидеть сервер базы данных, который аутентифицирует пользователей в приложении.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)
Теперь вы создали основной файл для приложения. На следующем этапе вы протестируете приложение.
Шаг 6 — Тестирование приложения
На этом этапе вы запустите свое приложение, чтобы проверить, работает ли механизм кэширования Redis. Выполните команды ниже, чтобы протестировать приложение:
Используйте следующую команду
python3
для запуска приложения:python3 index.py
Убедитесь, что пользовательский веб-сервер приложения запущен:
Web server is running on port 8080...
Установите еще одно соединение
SSH
с вашим сервером в новом окне терминала и выполните следующие командыcurl
, чтобы отправить четыре запроса GET с помощьюjohn_doe's
учетные данные. Добавьте[1-4]
в конец URL-адресаhttp://localhost:8080/
, чтобы отправить четыре запроса одной командой:curl -X GET -u john_doe:password_1 http://localhost:8080/[1-4]
Проверьте следующие выходные данные. Сервер MySQL обслуживает только первый запрос аутентификации. Затем база данных Redis обслуживает следующие три запроса.
[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"}
Логика вашего приложения теперь работает должным образом.
Заключение
В этом руководстве вы создали приложение Python, которое использует сервер Redis для кэширования учетных данных пользователей. Redis — это высокодоступный и масштабируемый сервер баз данных, который может выполнять тысячи транзакций в секунду. Благодаря механизму кэширования Redis в вашем приложении вы можете значительно снизить трафик на внутреннем сервере базы данных. Чтобы узнать больше о приложениях Redis, обратитесь к нашим руководствам по Redis.