Become a sponsor

FastAPI 应用的性能调优涉及 Uvicorn Worker 配置、数据库连接池、Redis 缓存策略、慢查询优化等多个层面。合理的调优能显著提升并发处理能力和响应速度。
性能调优原则
# 单 Worker(开发环境)
python src/main.py
# 多 Worker(生产环境)
uvicorn main:app --app-dir src --host 0.0.0.0 --port 8031 --workers 4Worker 数量公式
推荐 Worker 数量 = CPU 核心数 * 2 + 1
例如 4 核 CPU:workers = 4 * 2 + 1 = 9
查看 CPU 核心数:
# Linux
nproc
# Python
import multiprocessing; print(multiprocessing.cpu_count())| 方式 | 适用场景 | 特点 |
|---|---|---|
python src/main.py | 开发调试 | 单进程,自动重载 |
uvicorn --workers N | 生产部署 | 多进程,无自动重载 |
gunicorn -k uvicorn.workers.UvicornWorker | 生产部署 | 更成熟的进程管理 |
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 50max-requests 作用
--max-requests 1000 表示每个 Worker 处理 1000 个请求后自动重启,防止内存泄漏累积。--max-requests-jitter 50 添加随机抖动,避免所有 Worker 同时重启。
SQLAlchemy 连接池配置(在 core/config/database.py 中):
# 连接池配置
SQLALCHEMY_POOL_SIZE = 20 # 连接池大小
SQLALCHEMY_MAX_OVERFLOW = 10 # 超出池大小的最大连接数
SQLALCHEMY_POOL_TIMEOUT = 30 # 获取连接超时(秒)
SQLALCHEMY_POOL_RECYCLE = 3600 # 连接回收时间(秒)连接池大小
连接池总连接数 = pool_size + max_overflow。需确保不超过数据库的 max_connections 限制,否则会报连接数超限错误。
MySQL 查看最大连接数:
SHOW VARIABLES LIKE 'max_connections';# 获取连接池状态
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,未命中再查 DB |
| 写失效 | 数据更新时 | 更新 DB 后删除 Redis 缓存 |
| 预热 | 服务启动时 | 启动后主动加载热点数据到 Redis |
# 字典数据:较长 TTL(变更频率低)
DICT_CACHE_TTL = 3600 # 1 小时
# 用户权限:中等 TTL(登录时刷新)
PERM_CACHE_TTL = 1800 # 30 分钟
# 验证码:短 TTL(一次性使用)
CAPTCHA_CACHE_TTL = 300 # 5 分钟# 服务启动时预热缓存
async def warmup_cache():
"""预热字典、配置等热点数据"""
from utils.dict_util import refresh_dict_cache
await refresh_dict_cache()MySQL:
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 * | 只查询需要的字段 |
# 模型定义中添加索引
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'),
)# 避免大分页:使用游标分页
# 差: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()# 纯 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()
# ...禁止混用
禁止在 async def 端点中直接调用同步 DB 查询(会阻塞事件循环)。同步 DB 操作要么用 def 端点(自动线程池),要么用 asyncio.to_thread() 包裹。
性能调优的核心路径:Uvicorn 多 Worker 利用多核 CPU、数据库连接池匹配并发需求、Redis 缓存减少 DB 压力、索引和查询优化降低慢查询。建议先用监控数据定位瓶颈,再针对性调优,每次只调整一个参数并观察效果。