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

209 lines
5.6 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.
# 性能调优
## 概述
FastAPI 应用的性能调优涉及 Uvicorn Worker 配置、数据库连接池、Redis 缓存策略、慢查询优化等多个层面。合理的调优能显著提升并发处理能力和响应速度。
:::tip 性能调优原则
1. 先测量,后优化:用数据说话,避免盲目调参
2. 瓶颈优先:找到最大瓶颈,集中优化
3. 渐进式:每次只调整一个参数,观察效果
:::
## Uvicorn Worker 配置
### Worker 数量
```bash
# 单 Worker(开发环境)
python src/main.py
# 多 Worker(生产环境)
uvicorn main:app --app-dir src --host 0.0.0.0 --port 8031 --workers 4
```
:::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 src/main.py` | 开发调试 | 单进程,自动重载 |
| `uvicorn --workers N` | 生产部署 | 多进程,无自动重载 |
| `gunicorn -k uvicorn.workers.UvicornWorker` | 生产部署 | 更成熟的进程管理 |
### Gunicorn 配置示例
```bash
pip install gunicorn
gunicorn main:app \
--chdir src \
--workers 4 \
--worker-class uvicorn.workers.UvicornWorker \
--bind 0.0.0.0:8031 \
--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 同时重启。
:::
## 数据库连接池
SQLAlchemy 连接池配置(在 `core/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 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
# 服务启动时预热缓存
async def warmup_cache():
"""预热字典、配置等热点数据"""
from utils.dict_util import refresh_dict_cache
await 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(base_model, base_db):
__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 self.db.query(self.model).filter(
self.model.id > after_id,
self._soft_col() == 0
).order_by(self.model.id.asc()).limit(limit).all()
```
## 异步与并发
### 同步/异步选择
```python
# 纯 DB CRUD:同步 def(FastAPI 自动线程池执行)
def get_position_list(request):
return position_service.get_page(request)
# 含 Redis/文件 IO:async def + await
async def get_captcha(request):
redis = await get_redis()
# ...
```
:::tip 禁止混用
禁止在 `async def` 端点中直接调用同步 DB 查询(会阻塞事件循环)。同步 DB 操作要么用 `def` 端点(自动线程池),要么用 `asyncio.to_thread()` 包裹。
:::
## 总结
性能调优的核心路径:Uvicorn 多 Worker 利用多核 CPU、数据库连接池匹配并发需求、Redis 缓存减少 DB 压力、索引和查询优化降低慢查询。建议先用监控数据定位瓶颈,再针对性调优,每次只调整一个参数并观察效果。