如何优化 Flask 应用的性能

0 股票
0
0
0
0

介绍

Flask 是一个轻量级且灵活的 Web 框架,适用于构建中小型应用程序。它广泛应用于各种项目中,从简单的个人博客到更复杂的应用程序,例如 REST API、SaaS 平台、电子商务网站和数据驱动型仪表板。.

然而,随着应用程序流量或复杂性的增加,您可能会遇到性能瓶颈。无论您是构建内容管理系统 (CMS)、移动应用程序 API,还是实时数据可视化工具,优化 Flask 性能对于提供响应迅速且可扩展的用户体验都至关重要。.

在本教程中,您将探索优化 Flask 应用程序性能的技巧和最佳实践。.

先决条件
  • 一台运行 Ubuntu 系统的服务器,一个拥有 sudo 权限的非 root 用户,以及一个已启用的防火墙。有关如何设置此配置的说明,请从列表中选择您的 Ubuntu 发行版,并按照我们的服务器入门指南进行操作。请确保您运行的是受支持的 Ubuntu 版本。.
  • 了解 Linux 命令行 要了解命令行的入门知识或复习相关内容,您可以查看这篇 Linux 命令行入门指南。
  • 具备Python编程基础知识。.
  • 您的Ubuntu系统已安装Python 3.7或更高版本。要了解如何在Ubuntu上运行Python脚本,您可以参考我们的Ubuntu Python脚本运行教程。.

设置 Flask 环境

Ubuntu 24.04 默认安装了 Python 3。打开终端并运行以下命令来再次确认你的 Python 3 安装是否正确:

root@ubuntu:~# python3 --version
Python 3.12.3

如果您的计算机上已安装 Python 3,则上述命令将返回当前 Python 3 的版本。如果尚未安装,您可以运行以下命令来获取 Python 3 的安装版本:

root@ubuntu:~# sudo apt install python3

接下来,您需要在系统上安装 pip 包安装程序:

root@ubuntu:~# sudo apt install python3-pip

安装完 pip 之后,我们来安装 Flask。.

您将通过 pip 安装 Flask。建议在虚拟环境中进行此操作,以避免与系统上的其他软件包发生冲突。.

root@ubuntu:~# python3 -m venv myprojectenv
root@ubuntu:~# source myprojectenv/bin/activate
root@ubuntu:~# pip install Flask

创建一个 Flask 应用程序

下一步是编写 Flask 应用的 Python 代码。要创建新脚本,请转到您选择的目录:

root@ubuntu:~# cd ~/path-to-your-script-directory

进入该目录后,创建一个名为 app.py 的新 Python 文件,并导入 Flask。接下来,初始化一个 Flask 应用并创建根路径。.

root@ubuntu:~# nano app.py

这将打开一个空白文本编辑器。请在此处编写您的逻辑,或复制以下代码:

from flask import Flask, jsonify, request
app = Flask(__name__)
# Simulate a slow endpoint
@app.route('/slow')
def slow():
import time
time.sleep(2) # to simulate a slow response
return jsonify(message="This request was slow!")
# Simulate an intensive database operation
@app.route('/db')
def db_operation():
# This is a dummy function to simulate a database query
result = {"name": "User", "email": "[email protected]"}
return jsonify(result)
# Simulate a static file being served
@app.route('/')
def index():
return "<h1>Welcome to the Sample Flask App</h1>"
if __name__ == '__main__':
app.run(debug=True)

现在让我们运行 Flask 应用程序:

root@ubuntu:~# flask run

您可以使用以下 curl 命令测试端点:

测试 / 端点(返回静态内容):

root@ubuntu:~# curl http://127.0.0.1:5000/
[secondary_lebel Output]
<h1>Welcome to the Sample Flask App</h1>%

测试端点/慢速(模拟慢速响应):

root@ubuntu:~# time curl http://127.0.0.1:5000/db

为了检查这个慢速端点,我们使用 Linux 中的 time 命令。time 命令用于测量特定命令或程序的执行时间。它提供三项主要信息:

  1. 实时:从命令开始到结束所经过的实际时间。.
  2. 用户时间:CPU 在用户模式下花费的时间量。.
  3. 系统时间:CPU 在内核模式下花费的时间量。.

这将帮助我们测量慢速端点的实际运行时间。输出结果可能如下所示:

Output
{"message":"This request was slow!"}
curl http://127.0.0.1:5000/slow 0.00s user 0.01s system 0% cpu 2.023 total

此请求大约需要 2 秒钟才能响应,因为 time.sleep(2) 调用模拟了慢速响应。.

让我们测试一下 /db 端点(模拟数据库操作):

root@ubuntu:~# curl http://127.0.0.1:5000/db
Output
{"email":"[email protected]","name":"User"}

通过使用 curl 测试这些端点,您可以验证您的 Flask 应用程序是否正常运行,以及响应是否符合预期。.

下一节,您将学习如何使用各种技术来优化应用程序性能。.

使用生产就绪的 WSGI 服务器

Flask 内置的开发服务器并非为生产环境设计。为了有效处理并发请求,您应该迁移到像 Gunicorn 这样适用于生产环境的 WSGI 服务器。.

安装并启动 Gunicorn

我们来安装Gunicorn。

root@ubuntu:~# pip install gunicorn

使用 Gunicorn 运行 Flask 应用程序,并设置 4 个工作进程:

root@ubuntu:~# gunicorn -w 4 -b 0.0.0.0:8000 app:app
Output
% /Library/Python/3.9/bin/gunicorn -w 4 -b 0.0.0.0:8000 app:app
[2024-09-13 18:37:24 +0530] [99925] [INFO] Starting gunicorn 23.0.0
[2024-09-13 18:37:24 +0530] [99925] [INFO] Listening at: http://0.0.0.0:8000 (99925)
[2024-09-13 18:37:24 +0530] [99925] [INFO] Using worker: sync
[2024-09-13 18:37:24 +0530] [99926] [INFO] Booting worker with pid: 99926
[2024-09-13 18:37:25 +0530] [99927] [INFO] Booting worker with pid: 99927
[2024-09-13 18:37:25 +0530] [99928] [INFO] Booting worker with pid: 99928
[2024-09-13 18:37:25 +0530] [99929] [INFO] Booting worker with pid: 99929
[2024-09-13 18:37:37 +0530] [99925] [INFO] Handling signal: winch
^C[2024-09-13 18:38:51 +0530] [99925] [INFO] Handling signal: int
[2024-09-13 18:38:51 +0530] [99927] [INFO] Worker exiting (pid: 99927)
[2024-09-13 18:38:51 +0530] [99926] [INFO] Worker exiting (pid: 99926)
[2024-09-13 18:38:51 +0530] [99928] [INFO] Worker exiting (pid: 99928)
[2024-09-13 18:38:51 +0530] [99929] [INFO] Worker exiting (pid: 99929)
[2024-09-13 18:38:51 +0530] [99925] [INFO] Shutting down: Master

使用 Gunicorn 的好处如下:

  • 并发请求处理:Gunicorn 允许使用多个工作进程同时处理多个请求。.
  • 负载均衡:在各个工作进程之间均衡分配传入请求,确保服务器资源的最佳利用。.
  • 异步工作进程:借助像 gevent 这样的异步工作进程,可以高效地执行长时间运行的任务,而不会阻塞其他请求。.
  • 可扩展性:Gunicorn 可以通过增加工作进程的数量来处理更多并发请求,从而实现横向扩展。.
  • 容错性:自动替换无响应或损坏的工作进程,确保高可用性。.
  • 生产就绪:与 Flask 开发服务器不同,Gunicorn 针对生产环境进行了优化,具有更好的安全性、稳定性和性能特性。.

通过将生产环境切换到 Gunicorn,您可以显著提高 Flask 应用程序的吞吐量和响应速度,使其能够高效地处理真实世界的流量。.

启用缓存以减少负载。

缓存是提升 Flask 性能、减少系统开销的最佳方法之一。这里,我们添加了 Flask-Caching 来缓存慢速路径的执行结果。.

安装并配置 Flask-Caching 和 Redis

安装必要的软件包:

root@ubuntu:~# pip install Flask-Caching redis

更新 app.py 文件,为 slow/path 添加缓存。

打开编辑器,使用以下命令更新 app.py 文件:

root@ubuntu:~# nano app.py
from flask_caching import Cache
app = Flask(__name__)
# Configure Flask-Caching with Redis
app.config['CACHE_TYPE'] = 'redis'
app.config['CACHE_REDIS_HOST'] = 'localhost'
app.config['CACHE_REDIS_PORT'] = 6379
cache = Cache(app)
@app.route('/slow')
@cache.cached(timeout=60)
def slow():
import time
time.sleep(2) # Simulate a slow response
return jsonify(message="This request was slow!")

首次向 /slow 发送请求后,后续请求将在 60 秒内从缓存中处理,绕过 time.sleep() 函数。这可以降低服务器负载并提高响应速度。.

注意:本教程使用本地主机作为 Redis 主机。但是,在生产环境中,建议使用托管式 Redis 服务,例如 DigitalOcean Managed Redis。这样可以为您的存储需求提供更好的可扩展性、可靠性和安全性。您可以参考这篇关于在应用平台上使用 DigitalOcean Redis 进行存储的教程,了解更多关于将 DigitalOcean Managed Redis 集成到生产级应用程序中的信息。.

 

为了检查数据是否被缓存,我们对 /slow 端点运行以下命令。.

这是对 /slow 端点的第一个请求。此请求完成后,/slow 路由的结果将被缓存。.

root@ubuntu:~# time curl http://127.0.0.1:5000/slow
Output
{"message":"This request was slow!"}
curl http://127.0.0.1:5000/slow 0.00s user 0.01s system 0% cpu 2.023 total

这是在 60 秒内对 /slow 端点的后续请求:

root@ubuntu:~# time curl http://127.0.0.1:5000/slow
Output
{"message":"This request was slow!"}
curl http://127.0.0.1:5000/slow 0.00s user 0.00s system 0% cpu 0.015 total

优化数据库查询

数据库查询经常会成为性能瓶颈。在本节中,您将使用 SQLAlchemy 和连接池来模拟数据库查询优化。.

模拟带有连接聚合的数据库查询

首先,我们来安装 SQLAlchemy。

root@ubuntu:~# pip install Flask-SQLAlchemy

更新 app.py 文件以配置连接集成。

rom flask_sqlalchemy import SQLAlchemy
from sqlalchemy import text
# Simulate an intensive database operation
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///test.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
app.config['SQLALCHEMY_POOL_SIZE'] = 5 # Connection pool size
db = SQLAlchemy(app)
@app.route('/db1')
def db_operation_pooling():
# Simulate a database query
result = db.session.execute(text('SELECT 1')).fetchall()
return jsonify(result=str(result))

现在,当我们向 db1 路径执行 curl 请求时,应该会看到以下输出:

root@ubuntu:~# curl http://127.0.0.1:5000/db1 
output
{"result":"[(1,)]"}

在生产环境中实施连接池可以显著优化 Flask 应用的性能。连接池允许应用重用现有的数据库连接,而不是为每个请求创建新连接。这减少了创建新连接的开销,从而加快了响应速度并提高了可扩展性。.

我们之前设置的 SQLALCHEMY_POOL_SIZE 配置限制了连接池中的连接数。在生产环境中,您应该根据具体需求和服务器性能调整此值。此外,您可能还需要考虑其他集成选项,例如 SQLALCHEMY_MAX_OVERFLOW(用于在连接池已满时允许更多连接)和 SQLALCHEMY_POOL_TIMEOUT(用于指定请求等待连接的时间)。.

请记住,虽然我们的示例为了简单起见使用了 SQLite,但在实际应用中,您很可能会使用更强大的数据库,例如 PostgreSQL 或 MySQL。这些数据库拥有自己的连接池机制,可以与 SQLAlchemy 的集成结合使用,从而获得更好的性能。.

通过精心配置和使用连接池,您可以确保 Flask 应用程序即使在高负载下也能高效地执行数据库操作,从而显著提高其整体性能。.

启用 Gzip 压缩

压缩响应可以大幅减少服务器和客户端之间传输的数据量,从而提高性能。.

安装并配置 Flask-Compress

让我们安装 Flask-compress 包。.

root@ubuntu:~# pip install Flask-Compress

接下来,我们更新 app.py 以启用压缩功能。.

from flask_compress import Compress
# This below command enables Gzip compression for the Flask app
# It compresses responses before sending them to clients,
# reducing data transfer and improving performance
Compress(app)
@app.route('/compress')
def Compress():
return "<h1>Welcome to the optimized Flask app !</h1>"

它会自动压缩大于 500 字节的响应,从而减少大型响应的传输时间。.

在生产环境中,Gzip 压缩可以显著减少服务器和客户端之间传输的数据量,特别是对于 HTML、CSS 和 JavaScript 等基于文本的内容。.

数据传输量的减少可以加快页面加载速度,提升用户体验,并降低带宽成本。此外,许多现代浏览器都自动支持 Gzip 压缩,使其成为一种完全兼容的优化技术。启用 Gzip 压缩后,无需在客户端进行任何更改,即可有效提升 Flask 应用的性能和可扩展性。.

将密集型任务上传到 Celery

对于发送电子邮件或处理大型数据集等资源密集型操作,最好使用 Celery 将其卸载到后台作业中。这样可以防止长时间运行的任务阻塞传入的请求。.

Celery 是一个强大的分布式任务队列系统,它允许你异步执行耗时的任务。通过将密集型操作卸载到 Celery,你可以显著提升 Flask 应用的响应速度和可扩展性。Celery 的工作原理是将任务委派给运行在不同机器上的工作进程,从而实现更高效的资源利用和并行处理。.

使用芹菜的主要好处包括:

  1. 提高用户请求的响应速度
  2. 更好的可扩展性和资源管理
  3. 能够在不阻塞主程序的情况下执行复杂且耗时的任务。
  4. 内置任务调度和重试失败任务的支持
  5. 可轻松与 RabbitMQ 或 Redis 等各种消息代理集成

使用 Celery,您可以确保 Flask 应用程序即使在处理计算密集型或 I/O 密集型任务时也能保持响应。.

配置 Celery 以执行后台任务

我们来安装 Celery。.

root@ubuntu:~# pip install Celery

接下来,我们更新 app.py 文件,配置 Celery 以处理异步任务:

from celery import Celery
celery = Celery(app.name, broker='redis://localhost:6379/0')
@celery.task
def long_task():
import time
time.sleep(10) # Simulate a long task
return "Task Complete"
@app.route('/start-task')
def start_task():
long_task.delay()
return 'Task started'

在另一个终端中,启动 Celery 工作进程:

root@ubuntu:~# celery -A app.celery worker --loglevel=info
Output
------------- celery@your-computer-name v5.2.7 (dawn-chorus)
--- ***** ----- 
-- ******* ---- Linux-x.x.x-x-generic-x86_64-with-glibc2.xx 2023-xx-xx
- *** --- * --- 
- ** ---------- [config]
- ** ---------- .> app: app:0x7f8b8c0b3cd0
- ** ---------- .> transport: redis://localhost:6379/0
- ** ---------- .> results: disabled://
- *** --- * --- .> concurrency: 8 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** ----- 
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. app.long_task
[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] Connected to redis://localhost:6379/0
[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] mingle: searching for neighbors
[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] mingle: all alone
[2023-xx-xx xx:xx:xx,xxx: INFO/MainProcess] celery@your-computer-name ready.

现在运行 curl 命令访问 /start-task 路径,输出结果如下:

root@ubuntu:~# curl http://127.0.0.1:5000/start-task
Output
Task started

即使后台作业仍在运行,此操作也会几乎立即返回«任务已启动»。.

start_task() 函数执行两项操作:

  • 调用 long_task.delay(),异步启动 Celery 任务。这意味着任务会被加入后台运行队列,但函数不会等待任务完成。.
  • 它立即返回字符串«任务已启动»。.

需要注意的是,实际的耗时任务(通过 10 秒的睡眠模拟)是由 Celery 异步执行的。Flask 路由不会等待该任务完成就响应请求。.

所以,当你搞砸这个端点时,你会立即收到«作业已启动»的响应,而实际作业会在后台继续运行 10 秒钟。.

后台任务完成后,10 秒后您应该会看到以下报告消息:

输出结果将类似于这样:

[2024-xx-xx xx:xx:xx,xxx: INFO/MainProcess] Task app.long_task[task-id] received
[2024-xx-xx xx:xx:xx,xxx: INFO/ForkPoolWorker-1] Task app.long_task[task-id] succeeded in 10.xxxs: 'Task Complete'

此示例展示了 Celery 如何通过异步执行耗时任务来提升 Flask 应用的性能,从而保持主应用的响应速度。耗时任务在后台运行,使 Flask 应用能够处理其他请求。.

在生产环境中运行 Celery 涉及以下步骤:

  1. 使用像 RabbitMQ 这样强大的消息代理
  2. 使用专有的结果后端(例如 PostgreSQL)
  3. 利用流程控制系统(例如,主管)管理员工
  4. 实施监控工具(例如,鲜花监控系统),加强错误处理和日志记录
  5. 加强错误处理和日志记录
  6. 使用任务优先级排序
  7. 使用不同机器上的多个工作进程进行扩展
  8. 确保采取适当的安全措施

结果

在本教程中,您学习了如何通过实施各种性能增强技术来优化 Flask 应用程序。按照这些步骤操作,您可以提高 Flask 应用程序的性能、可扩展性和响应速度,确保其即使在高负载下也能高效运行。.

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

您可能也喜欢