Поиск по сайту:

Как ускорить обработку сеансов приложений 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. Для установки драйверов выполните следующие действия:

  1. Обновите индекс информации о пакете и выполните следующую команду, чтобы установить python3-pip, менеджер пакетов Python, позволяющий устанавливать дополнительные модули, не входящие в стандартную библиотеку Python.
sudo apt install python3-pip
  1. Установите драйвер MySQL для Python:
pip install mysql-connector-python
  1. Установите драйвер Redis для Python:
pip install redis

После установки необходимых драйверов для связи с MySQL и Redis перейдите к следующему шагу и инициализируйте базу данных MySQL.

Шаг 2 — Настройка образца базы данных MySQL

Для этого руководства вам понадобится одна таблица MySQL. В производственной среде у вас могут быть десятки таблиц, которые обслуживают другие запросы. Настройте базу данных и создайте таблицу, выполнив следующие команды:

  1. Войдите на сервер базы данных MySQL как пользователь root:

    sudo mysql -u root -p
  2. При появлении запроса введите пароль 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;

  1. Убедитесь, что вы получили следующий вывод, подтверждающий успешное выполнение предыдущих команд:

    Query OK, 1 row affected (0.01 sec)
  2. Переключитесь на новую базу данных company:

    1. Подтвердите, что вы подключены к новой базе данных, проверив следующий вывод:

      Database changed
    2. Создайте таблицу 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;
    3. Убедитесь, что вы создали новую таблицу, проверив следующий вывод:

      Query OK, 0 rows affected (0.03 sec)
    4. Заполните таблицу system_users примерами данных. Используйте встроенную функцию MySQL MD5(...) для хэширования пароля в целях безопасности:

      1. INSERT INTO system_users (имя пользователя, имя, фамилия, пароль) VALUES ('mary_henry', 'MARY', 'HENRY', MD5('password_2'));
      2. INSERT INTO system_users (имя пользователя, имя, фамилия, пароль) ЗНАЧЕНИЯ ('peter_jade', 'PETER', 'JADE', MD5('password_3'));
    5. Проверьте вывод ниже:

      Query OK, 1 row affected (0.00 sec)
    6. Запросите таблицу system_users, чтобы убедиться, что данные на месте:

      1. ID пользователя,
      2. имя,
      3. фамилия,
      4. пароль
      5. ОТ системных_пользователей;
    7. Проверьте следующий вывод:

      +---------+------------+-----------+----------------------------------+| 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)
    8. Выйдите из базы данных MySQL:

      Теперь вы настроили подходящую базу данных MySQL для своего приложения. На следующем шаге вы создадите модуль Python, взаимодействующий с вашим примером базы данных.

      Шаг 3 — Создание центрального модуля шлюза MySQL для Python

      При кодировании любого проекта Python вам следует создать отдельный модуль для каждой задачи, чтобы обеспечить возможность повторного использования кода. На этом этапе вы настроите центральный модуль, который позволит вам подключаться и отправлять запросы к базе данных MySQL из сценария Python. Выполните следующие действия:

      1. Создайте каталог project. Этот каталог отделяет файлы исходного кода Python от остальных системных файлов:

        1. Перейдите в новый каталог project:

          1. Используйте текстовый редактор nano, чтобы открыть новый файл mysql_db.py. В этом файле находится модуль Python, который взаимодействует с базой данных MySQL:

            nano mysql_db.py
          2. Введите следующую информацию в файл 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]
          3. Сохраните и закройте файл 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. Выполните следующие шаги:

          1. Откройте новый файл redis_db.py:

            nano redis_db.py
          2. Введите следующую информацию в файл 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
          3. Сохраните и закройте файл redis_db.py.

          • В приведенном выше файле есть один класс (RedisDb:).

          • В этом классе метод db_con(self): использует предоставленные учетные данные для подключения к серверу Redis и возвращает повторно используемое соединение с помощью оператора return redis_con.

          После настройки класса Redis на следующем шаге создайте основной файл для вашего проекта.

          Шаг 5 — Создание точки входа приложения

          Каждое приложение Python должно иметь точку входа или основной файл, который выполняется при запуске приложения. В этом файле вы создадите код, который показывает время текущего сервера для аутентифицированных пользователей. Этот файл использует созданные вами пользовательские модули MySQL и Redis для аутентификации пользователей. Чтобы создать файл, выполните следующие действия:

          1. Откройте новый файл index.py:

            nano index.py
          2. Введите следующую информацию в файл 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.")
          3. Сохраните и закройте файл 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. Выполните команды ниже, чтобы протестировать приложение:

          1. Используйте следующую команду python3 для запуска приложения:

            python3 index.py
          2. Убедитесь, что пользовательский веб-сервер приложения запущен:

            Web server is running on port 8080...
          3. Установите еще одно соединение 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]
          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.