Files
djangoadmin-wiki/DjangoAdmin_Flask_AntdVue/zh/volume6/performance.md
T
2026-09-12 23:12:15 +08:00

261 lines
6.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 性能调优
## 概述
Flask 应用的性能调优涉及 Gunicorn Worker 配置、数据库连接池、Redis 缓存策略、慢查询优化等多个层面。合理的调优能显著提升并发处理能力和响应速度。
:::tip 性能调优原则
1. 先测量,后优化:用数据说话,避免盲目调参
2. 瓶颈优先:找到最大瓶颈,集中优化
3. 渐进式:每次只调整一个参数,观察效果
:::
## Gunicorn Worker 配置
### Worker 数量
```bash
# 单 Worker(开发环境)
python app.py
# 多 Worker(生产环境)
gunicorn -w 4 -b 0.0.0.0:8021 app:app
```
:::tip Worker 数量公式
推荐 Worker 数量 = `CPU 核心数 * 2 + 1`
例如 4 核 CPU:`workers = 4 * 2 + 1 = 9`
查看 CPU 核心数:
```bash
# Linux
nproc
# Python
import multiprocessing; print(multiprocessing.cpu_count())
```
:::
### 启动方式选择
| 方式 | 适用场景 | 特点 |
|------|---------|------|
| `python app.py` | 开发调试 | 单进程,自动重载 |
| `gunicorn -w N` | 生产部署 | 多进程,无自动重载 |
| `gunicorn --threads N` | 生产部署 | 多线程模式 |
### Gunicorn 配置示例
```bash
pip install gunicorn
gunicorn app:app \
--workers 4 \
--bind 0.0.0.0:8021 \
--timeout 120 \
--keep-alive 5 \
--max-requests 1000 \
--max-requests-jitter 50
```
:::tip max-requests 作用
`--max-requests 1000` 表示每个 Worker 处理 1000 个请求后自动重启,防止内存泄漏累积。`--max-requests-jitter 50` 添加随机抖动,避免所有 Worker 同时重启。
:::
### Gunicorn 配置文件
创建 `gunicorn.conf.py` 配置文件:
```python
# gunicorn.conf.py
import multiprocessing
# 绑定地址
bind = "0.0.0.0:8021"
# Worker 数量
workers = multiprocessing.cpu_count() * 2 + 1
# Worker 类型
worker_class = "sync"
# 线程数(worker_class="gthread" 时生效)
threads = 2
# 超时时间
timeout = 120
# 保持连接
keepalive = 5
# 最大请求数(防止内存泄漏)
max_requests = 1000
max_requests_jitter = 50
# 日志
accesslog = "-"
errorlog = "-"
loglevel = "info"
```
使用配置文件启动:
```bash
gunicorn -c gunicorn.conf.py app:app
```
## 数据库连接池
SQLAlchemy 连接池配置(在 `config/database.py` 中):
```python
# 连接池配置
SQLALCHEMY_POOL_SIZE = 20 # 连接池大小
SQLALCHEMY_MAX_OVERFLOW = 10 # 超出池大小的最大连接数
SQLALCHEMY_POOL_TIMEOUT = 30 # 获取连接超时(秒)
SQLALCHEMY_POOL_RECYCLE = 3600 # 连接回收时间(秒)
```
:::warning 连接池大小
连接池总连接数 = `pool_size + max_overflow`。需确保不超过数据库的 `max_connections` 限制,否则会报连接数超限错误。
MySQL 查看最大连接数:
```sql
SHOW VARIABLES LIKE 'max_connections';
```
:::
### 连接池监控
```python
# 获取连接池状态
from src.core.database import engine
pool = engine.pool
print(f"池大小: {pool.size()}")
print(f"已签出: {pool.checkedout()}")
print(f"空闲数: {pool.checkedin()}")
print(f"溢出数: {pool.overflow()}")
```
## Redis 缓存优化
### 缓存策略
| 策略 | 适用场景 | 实现方式 |
|------|---------|---------|
| 读缓存 | 字典、配置等读多写少 | 查询时先读 Redis,未命中再查 DB |
| 写失效 | 数据更新时 | 更新 DB 后删除 Redis 缓存 |
| 预热 | 服务启动时 | 启动后主动加载热点数据到 Redis |
### TTL 设置建议
```python
# 字典数据:较长 TTL(变更频率低)
DICT_CACHE_TTL = 3600 # 1 小时
# 用户权限:中等 TTL(登录时刷新)
PERM_CACHE_TTL = 1800 # 30 分钟
# 验证码:短 TTL(一次性使用)
CAPTCHA_CACHE_TTL = 300 # 5 分钟
```
### 缓存预热
```python
# 服务启动时预热缓存
def warmup_cache():
"""预热字典、配置等热点数据"""
from src.common.utils.dict_util import refresh_dict_cache
refresh_dict_cache()
```
## 慢查询优化
### 开启慢查询日志
MySQL:
```sql
SET GLOBAL slow_query_log = ON;
SET GLOBAL long_query_time = 1;
SET GLOBAL slow_query_log_file = '/var/log/mysql/slow.log';
```
### 常见优化手段
| 问题 | 优化方案 |
|------|---------|
| 缺少索引 | 为 WHERE/ORDER BY 字段添加索引 |
| 全表扫描 | 使用 EXPLAIN 分析查询计划 |
| N+1 查询 | 使用 joinedload/subqueryload 预加载关联数据 |
| 大分页 | 使用游标分页或延迟关联 |
| SELECT * | 只查询需要的字段 |
### 索引优化示例
```python
# 模型定义中添加索引
class Article(BaseModel, BaseDB):
__tablename__ = DB_PREFIX + "article"
title = Column(String(255), index=True) # 单列索引
status = Column(Integer, index=True)
category_id = Column(Integer, index=True)
# 复合索引(在 __table_args__ 中定义)
__table_args__ = (
Index('idx_status_category', 'status', 'category_id'),
)
```
### 分页查询优化
```python
# 避免大分页:使用游标分页
# 差:OFFSET 100000 LIMIT 10(扫描大量数据)
# 好:WHERE id > last_id LIMIT 10(利用主键索引)
def paginate_after_id(self, after_id: int, limit: int = 10):
"""游标分页:基于上次最后一条记录的 ID"""
return cls.model.query.filter(
cls.model.id > after_id,
cls.model.is_delete == 0
).order_by(cls.model.id.asc()).limit(limit).all()
```
## 同步架构优化
### 线程池配置
Flask 使用 Gunicorn 的 sync worker,每个 worker 处理一个请求。可以通过多 worker 和多线程提升并发:
```bash
# 多 worker + 多线程
gunicorn app:app \
--workers 4 \
--threads 2 \
--worker-class gthread \
--bind 0.0.0.0:8021
```
### 异步任务
对于耗时操作(如邮件发送、文件处理),使用 Celery 等异步任务队列:
```python
from celery import Celery
celery = Celery('tasks', broker='redis://localhost:6379/0')
@celery.task
def send_email(to, subject, body):
"""异步发送邮件"""
# 发送邮件逻辑
pass
```
## 总结
性能调优的核心路径:Gunicorn 多 Worker 利用多核 CPU、数据库连接池匹配并发需求、Redis 缓存减少 DB 压力、索引和查询优化降低慢查询。建议先用监控数据定位瓶颈,再针对性调优,每次只调整一个参数并观察效果。