1. 环境准备与基础配置
第一次用FastAPI部署项目时,我对着报错信息折腾到凌晨三点。后来才发现,很多问题其实在环境配置阶段就能避免。咱们先从最基础的虚拟环境说起,这玩意儿就像给你的项目单独准备一个工具箱,不会和其他项目打架。
创建虚拟环境其实特别简单,但Windows和Linux/macOS的命令稍有不同:
# Windows系统 python -m venv venv .\venv\Scripts\activate # Linux/macOS python3 -m venv venv source venv/bin/activate激活后看到命令行前面出现(venv)就说明成功了。这里有个坑我踩过好几次——如果你同时安装了Python2和Python3,一定要确认用的是python3命令。有次我死活装不上FastAPI,后来发现一直在用Python2.7的环境。
安装依赖时别像我当初那样傻乎乎一个个pip install。直接建个requirements.txt文件,把需要的包都列进去:
fastapi==0.95.2 uvicorn==0.22.0 sqlalchemy==2.0.15 psycopg2-binary==2.9.6 python-jose==3.3.0 passlib==1.7.4然后一条命令搞定所有安装:
pip install -r requirements.txt2. 应用启动与基础调试
第一次运行FastAPI应用时,我对着404错误一脸懵逼。后来才发现是启动方式有问题。Uvicorn作为ASGI服务器,启动命令里的main:app这个参数特别关键:
uvicorn main:app --reload --host 0.0.0.0 --port 8000这里的main指的是你的Python文件名(不带.py后缀),app是文件里的FastAPI实例变量名。比如你的文件叫server.py,里面写的是api = FastAPI(),那启动命令就得改成:
uvicorn server:api --reload--reload参数在开发时特别有用,改完代码自动重启服务。但千万别在生产环境用这个,性能会受影响。
测试接口时我发现个有趣现象:直接访问http://127.0.0.1:8000可能返回404,但http://127.0.0.1:8000/docs却能打开Swagger文档。这是因为没定义根路由。解决方法很简单,加个路由就行:
from fastapi import FastAPI app = FastAPI() @app.get("/") async def root(): return {"message": "Hello World"}3. 生产环境部署实战
第一次上生产环境时,我天真地直接用uvicorn启动,结果服务器一重启服务就挂了。后来学会了用systemd来管理服务进程。创建一个/etc/systemd/system/fastapi.service文件:
[Unit] Description=FastAPI Application After=network.target [Service] User=www-data WorkingDirectory=/path/to/your/project ExecStart=/path/to/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 Restart=always [Install] WantedBy=multi-user.target然后执行:
sudo systemctl daemon-reload sudo systemctl start fastapi sudo systemctl enable fastapi这样服务就会随系统启动,崩溃了也会自动重启。查看服务状态用:
sudo systemctl status fastapi4. Nginx反向代理配置
单独用FastAPI裸奔在外网太危险,得用Nginx当保镖。配置/etc/nginx/sites-available/yourdomain.com:
server { listen 80; server_name yourdomain.com; location / { proxy_pass http://localhost:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } }启用配置并测试:
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled sudo nginx -t sudo systemctl restart nginx这里有个大坑要注意:如果Nginx和FastAPI在同一台机器上,proxy_pass千万别用127.0.0.1,得用localhost。因为Nginx对IPv4和IPv6的处理方式不同,可能导致连接被拒绝。
5. HTTPS安全配置
现在没HTTPS都不好意思说自己是做Web的。用Certbot申请免费SSL证书:
sudo apt install certbot python3-certbot-nginx sudo certbot --nginx -d yourdomain.com证书自动续期测试:
sudo certbot renew --dry-runNginx的HTTPS配置会自动更新,但FastAPI这边也得调整。特别是当你的前端和后端分离部署时,得处理CORS问题:
from fastapi.middleware.cors import CORSMiddleware app.add_middleware( CORSMiddleware, allow_origins=["https://yourfrontend.com"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )千万别图省事用allow_origins=["*"],这会导致严重的安全漏洞。我就吃过这个亏,被安全团队发警告邮件。
6. 数据库连接优化
刚开始我用SQLAlchemy的同步模式,结果并发一高就崩。后来换成异步模式,性能直接起飞:
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker DATABASE_URL = "postgresql+asyncpg://user:password@localhost/dbname" engine = create_async_engine(DATABASE_URL) AsyncSessionLocal = sessionmaker(engine, class_=AsyncSession, expire_on_commit=False) async def get_db(): async with AsyncSessionLocal() as session: yield session在路由中使用时记得加async:
@app.get("/items/") async def read_items(db: AsyncSession = Depends(get_db)): result = await db.execute(select(Item)) return result.scalars().all()7. 静态文件处理
FastAPI处理静态文件有个坑:直接用它自带的StaticFiles中间件在生产环境性能不行。我的解决方案是用Nginx直接处理静态文件:
location /static/ { alias /path/to/your/static/files/; expires 30d; }如果非要让FastAPI处理,至少得开个缓存:
from fastapi.staticfiles import StaticFiles app.mount("/static", StaticFiles(directory="static"), name="static")8. 监控与日志
生产环境没有监控等于裸奔。我用Prometheus+Grafana来监控API性能。先装依赖:
pip install prometheus-fastapi-instrumentator然后在FastAPI中配置:
from prometheus_fastapi_instrumentator import Instrumentator Instrumentator().instrument(app).expose(app)这样就能在/metrics端点看到各种指标了。日志配置也很重要:
import logging from fastapi.logger import logger gunicorn_logger = logging.getLogger('gunicorn.error') logger.handlers = gunicorn_logger.handlers logger.setLevel(gunicorn_logger.level)9. 性能调优技巧
压测时发现几个性能瓶颈点,分享下优化经验:
- 使用Jinja2模板时开启缓存:
from fastapi.templating import Jinja2Templates templates = Jinja2Templates(directory="templates", auto_reload=False)- 启用Gzip压缩:
from fastapi.middleware.gzip import GZipMiddleware app.add_middleware(GZipMiddleware, minimum_size=1000)- 调整Uvicorn工作进程数(CPU核心数×2+1):
uvicorn main:app --workers 5 --host 0.0.0.0 --port 800010. 常见故障排查
最后分享几个我遇到的奇葩问题及解决方法:
- 数据库连接泄露:发现连接数暴涨,原来是在异常处理中忘了关闭session。现在都用contextmanager确保关闭:
from contextlib import asynccontextmanager @asynccontextmanager async def get_db(): session = AsyncSessionLocal() try: yield session finally: await session.close()- 时区问题:数据库时间和API返回时间不一致。统一用UTC:
from datetime import datetime, timezone def get_current_time(): return datetime.now(timezone.utc)- 内存泄漏:原来是忘了配置UVICORN的日志级别。在启动命令加个参数:
uvicorn main:app --log-level warning