引言
在本指南中,您将使用 Redis 数据库来加速 Ubuntu 服务器上的 Python/MySQL 应用程序的会话处理。
前提条件
要完成本教程,你需要:
需要一个已设置的Ubuntu服务器,具有非root用户,具有sudo
权限,并启用了防火墙以阻止非必要的端口。
设置完成后,以的非root用户身份登录并进行第一步。
建议使用至少有以下配置的服务器:
4 核心的 CPU,4GB 的内存
选择服务器提供商
为了本教程的演示,我将以一个具体的云服务提供商为例,展示如何进行操作。选择哪个提供商根据个人偏好和需求来决定。
以下步骤仅供参考,请根据实际需求选择配置。
购买云服务器
本示例中,我们选择了香港作为服务器区域。
点击 云产品 → 云服务器 → 立即购买
选择操作系统
在创建服务器实例时,选择 Ubuntu 作为操作系统。
连接到服务器
使用 X-shell 或偏好的 SSH 客户端,通过远程用户名和密码连接到服务器。成功连接后,将看到特定的欢迎信息,表明已成功登录。
- 切换到新的
sudo
用户账户并安装:- MySQL 服务器。
- Redis 服务器。
第 1 步 — 安装 Python 数据库驱动程序(Redis 和 MySQL)
这个应用程序永久存储用户的凭证,如姓名和密码,在 MySQL 数据库服务器中。当用户登录应用程序时,Python 脚本查询 MySQL 数据库并将详细信息与存储的值进行匹配。然后,Python 脚本将用户的登录凭证缓存在 Redis 数据库中,以服务于其他未来的请求。为了完成该逻辑,您的 Python 脚本需要数据库驱动程序(Python 模块)与 MySQL 和 Redis 服务器进行通信。按照以下步骤安装驱动程序:
- 更新您的包信息索引并运行以下命令以安装
python3-pip
,这是一个 Python 包管理器,允许您安装不属于 Python 标准库的额外模块。
sudo apt install python3-pip
- 安装 Python 的 MySQL 驱动程序:
pip install mysql-connector-python
- 安装 Python 的 Redis 驱动程序:
pip install redis
安装了与 MySQL 和 Redis 通信所需的驱动程序后,请进行下一步并初始化 MySQL 数据库。
第 2 步 — 设置示例 MySQL 数据库
对于本指南,您需要一个 MySQL 表。在生产环境中,您可以有数十个表来处理其他请求。通过执行以下命令设置数据库并创建表:
- 以
root
用户身份登录到 MySQL 数据库服务器:
sudo mysql -u root -p
- 输入您的 MySQL 服务器的
root
密码,然后按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;
- 确保您收到以下输出以确认之前的命令已成功运行:
OutputQuery OK, 1 row affected (0.01 sec)
- 切换到新的
company
数据库:
USE company;
- 确认您已连接到新数据库,通过验证以下输出:
OutputDatabase changed
- 创建一个
system_users
表。user_id
列作为PRIMARY KEY
以唯一标识每个用户。username
和password
列是用户必须提交的登录凭证,以登录应用程序。first_name
和last_name
列存储用户的姓名:
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;
- 确保您已创建新表,通过验证以下输出:
OutputQuery OK, 0 rows affected (0.03 sec)
- 用示例数据填充
system_users
表。使用 MySQL 内置的MD5(...)
函数来哈希密码以确保安全:
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'));
- 验证以下输出:
OutputQuery OK, 1 row affected (0.00 sec)
- 查询
system_users
表以确保数据已就位:
SELECT
user_id,
first_name,
last_name,
password
FROM system_users;
- 验证以下输出:
Output+---------+------------+-----------+----------------------------------+
| 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 数据库退出:
QUIT;
您现在已经为您的应用程序设置了正确的 MySQL 数据库。在下一步中,您将构建一个与您的示例数据库通信的 Python 模块。
第 3 步 — 为 Python 创建一个中心 MySQL 网关模块
在编写任何 Python 项目时,您应该为每个任务创建一个单独的模块,以促进代码重用。在这一步中,您将设置一个中心模块,允许您从 Python 脚本连接并查询 MySQL 数据库。按照以下步骤进行:
- 创建一个
project
目录。此目录将您的 Python 源代码文件与系统的其余文件分开:
mkdir project
- 切换到新的
project
目录:
cd project
- 使用
nano
文本编辑器打开一个新的mysql_db.py
文件。此文件托管与 MySQL 数据库通信的 Python 模块:
nano mysql_db.py
- 将以下信息输入到
mysql_db.py
文件中。将example-mysql-password
替换为company_user
账户的正确 MySQL 密码:
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]
- 保存并关闭
mysql_db.py
文件。
mysql_db.py
模块文件有一个类(MysqlDb:
)和两个方法:
db_con(self):
,连接到您之前创建的示例company
数据库,并返回一个可重用的 MySQL 连接。query(self, username, password):
,一个接受username
和password
并查询system_users
表以查找匹配项的方法。条件if row_count < 1: ... else: return result[1]
语句在表中找不到用户时返回布尔值False
,或者如果应用程序找到匹配项,则返回用户的密码(result[1]
)。
有了 MySQL 模块准备就绪,按照下一步
设置一个类似的 Redis 模块,与 Redis 键值存储通信。
第 4 步 — 为 Python 创建一个中心 Redis 模块
在这一步中,您将编写一个模块,连接到 Redis 服务器。执行以下步骤:
- 打开一个新的
redis_db.py
文件:
nano redis_db.py
- 将以下信息输入到
redis_db.py
文件中。将example-redis-password
替换为 Redis 服务器的正确密码:
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
- 保存并关闭
redis_db.py
文件。
- 上述文件有一个类(
RedisDb:
)。 - 在这个类下,
db_con(self):
方法使用提供的凭据连接到 Redis 服务器,并返回一个可重用的连接。
设置好 Redis 类后,下一步创建项目的主文件。
第 5 步 — 创建应用程序的入口点
每个 Python 应用程序都必须有一个入口点或主文件,当应用程序运行时执行。在该文件中,您将创建一个代码,显示当前服务器的时间给经过身份验证的用户。该文件使用您创建的自定义 MySQL 和 Redis 模块来验证用户。按照以下步骤创建文件:
- 打开一个新的
index.py
文件:
nano index.py
- 将以下信息输入到
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 running.")
- 保存并关闭
index.py
文件。
- 在
index.py
文件中,import...
部分将以下模块添加到您的项目中:utf_8
,base64
,md5
, 和json
,文本编码和格式化模块。http.server
,HTTPStatus
, 和socketserver
,Web 服务器模块。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_resp = mysql_server.query(auth_user, auth_password)
语句查询 MySQL 数据库服务器。如果用户提供的密码与数据库存储的值不匹配,应用程序返回 {"error": "Invalid username/password."}
错误。否则,应用程序使用 redis_client.set(auth_user, mysql_resp)
语句将用户详细信息缓存在 Redis 服务器中。
- 在所有用户凭证与 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 服务器正在运行:
OutputWeb server is running on port 8080...
- 在新终端窗口中建立另一个
SSH
连接到您的服务器,并运行以下curl
命令,使用john_doe's
凭证发送四个 GET 请求。在http://localhost:8080/
URL 后附加[1-4]
以在一个命令中发送四个请求:
curl -X GET -u john_doe:password_1 <http://localhost:8080/[1-4]>
您的应用程序逻辑现在按预期工作。
结论
在本指南中,您构建了一个使用 Redis 服务器缓存用户登录凭证的 Python 应用程序。Redis 是一个高可用且可扩展的数据库服务器,可以每秒执行数千次事务。通过在应用程序中使用 Redis 缓存机制,您可以大幅减少后端数据库服务器的流量。