Chapter 10 · 性能优化与部署:走向世界
📚 学完本章,你将能够:
- 用 Redis 缓存热点数据,减少数据库查询
- 给 API 添加限流,防止被突发流量击垮
- 用 Gunicorn + Uvicorn 部署生产环境
- 编写 Dockerfile 多阶段构建,减小镜像体积
- 配置 Nginx 反向代理、HTTPS 和 WebSocket 转发
💡 场景引入
你的图书 API 在小范围测试中表现良好。但上线第一天,首页书籍列表接口就被爬虫疯狂请求,数据库连接池耗尽,服务崩溃。
问题有三个:热门数据没缓存,每次请求都查数据库;没有限流,任何人可以无限请求;只跑了单进程,无法利用多核 CPU。本章解决这些问题,让你的服务能扛住真实流量。
10.1 缓存:把常用数据放内存
数据库查询通常是 API 最慢的一环。如果"热门书籍列表"每秒被请求 1000 次,每次都查数据库,数据库很快就会不堪重负。
缓存的思路是:第一次从数据库查出结果后,把它存到 Redis(内存数据库)里,后续请求直接读 Redis,速度快了几十倍。
Redis 缓存
import redis.asyncio as redis
from functools import wraps
r = redis.from_url("redis://localhost:6379")
async def get_books_cached():
# 先查缓存
cached = await r.get("books:popular")
if cached:
return json.loads(cached)
# 缓存未命中,查数据库
books = await fetch_books_from_db()
# 写入缓存,设置 60 秒过期
await r.setex("books:popular", 60, json.dumps(books))
return books
缓存一致性
数据更新后,缓存里的旧数据不会自动消失。写操作后必须主动删除缓存(await r.delete("books:popular")),否则用户会看到过期内容。
10.2 限流:防止被请求淹没
登录接口如果被暴力破解,每秒几千次请求,数据库会扛不住。slowapi 提供简单的限流装饰器:
限流
from slowapi import Limiter
from slowapi.util import get_remote_address
limiter = Limiter(key_func=get_remote_address)
app.state.limiter = limiter
@app.post("/auth/token")
@limiter.limit("5/minute")
async def login(...):
...
每个 IP 地址每分钟只能尝试 5 次登录。超限返回 429 Too Many Requests。
10.3 生产部署:Gunicorn + Uvicorn
开发时用 uvicorn main:app --reload,但生产环境需要多个进程同时处理请求,利用多核 CPU。
生产启动
gunicorn main:app \
-k uvicorn.workers.UvicornWorker \
-w 4 \
-b 0.0.0.0:8000 \
--access-logfile - \
--error-logfile -
| 参数 | 含义 |
|---|---|
-k uvicorn.workers.UvicornWorker | 使用 Uvicorn 作为 worker,支持 async |
-w 4 | 开 4 个 worker 进程,通常设为 (2 × CPU核数) + 1 |
--max-requests 10000 | 每个 worker 处理 1 万请求后自动重启,防内存泄漏 |
10.4 Docker:打包你的应用
Docker 让你的应用带着所有依赖一起部署,避免"在我电脑上能跑"的问题。
Dockerfile
# 构建阶段
FROM python:3.11-slim as builder
WORKDIR /app
RUN pip install poetry
COPY pyproject.toml poetry.lock ./
RUN poetry install --no-dev --no-interaction
# 运行阶段(只保留必要文件,镜像更小)
FROM python:3.11-slim
WORKDIR /app
COPY --from=builder /app/.venv /app/.venv
COPY . .
ENV PATH="/app/.venv/bin:$PATH"
CMD ["gunicorn", "main:app", "-k", "uvicorn.workers.UvicornWorker", "-w", "4", "-b", "0.0.0.0:8000"]
10.5 Nginx:守门的大将
Nginx 放在 Gunicorn 前面,负责:SSL 终止(HTTPS)、静态文件、压缩、反向代理、负载均衡。
nginx.conf
server {
listen 443 ssl http2;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
location / {
proxy_pass http://app:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# WebSocket 支持
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}
🎯 知识检测
问题 1
缓存数据更新后,为什么要主动删除缓存而不是等它过期?
解析:如果缓存 TTL 是 60 秒,数据更新后用户可能在 60 秒内一直看到旧内容。主动删除(Cache-Aside 模式)保证数据一致性。
问题 2
为什么生产环境用 Gunicorn + Uvicorn,而不是直接
uvicorn --reload?
解析:--reload 会监控文件变化并重启,有额外开销。生产环境需要多进程处理并发,Gunicorn 是成熟的进程管理器,UvicornWorker 让每个进程都能处理 async 请求。
问题 3
Nginx 在架构中的主要作用不包括?
解析:Nginx 是 Web 服务器/反向代理,不负责编译代码。它处理 HTTPS、静态文件、压缩、负载均衡和 WebSocket 转发。
本章小结
✓
缓存减少数据库压力
Redis 存热点数据,但更新后主动删除保证一致性。
✓
限流保护关键接口
登录、注册等接口必须限流,防止暴力破解和突发流量。
✓
Gunicorn 管理多进程
worker 数按 CPU 核心配置,max-requests 防内存泄漏。
✓
Docker + Nginx 是生产标配
容器化部署保证环境一致,Nginx 处理 HTTPS 和静态资源。