FastAPI部署实战:从零到生产的避坑指南

张开发
2026/7/2 13:47:07 15 分钟阅读
FastAPI部署实战:从零到生产的避坑指南
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文件把需要的包都列进去fastapi0.95.2 uvicorn0.22.0 sqlalchemy2.0.15 psycopg2-binary2.9.6 python-jose3.3.0 passlib1.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] DescriptionFastAPI Application Afternetwork.target [Service] Userwww-data WorkingDirectory/path/to/your/project ExecStart/path/to/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8000 Restartalways [Install] WantedBymulti-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.comserver { 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_credentialsTrue, allow_methods[*], allow_headers[*], )千万别图省事用allow_origins[*]这会导致严重的安全漏洞。我就吃过这个亏被安全团队发警告邮件。6. 数据库连接优化刚开始我用SQLAlchemy的同步模式结果并发一高就崩。后来换成异步模式性能直接起飞from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession from sqlalchemy.orm import sessionmaker DATABASE_URL postgresqlasyncpg://user:passwordlocalhost/dbname engine create_async_engine(DATABASE_URL) AsyncSessionLocal sessionmaker(engine, class_AsyncSession, expire_on_commitFalse) async def get_db(): async with AsyncSessionLocal() as session: yield session在路由中使用时记得加asyncapp.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(directorystatic), namestatic)8. 监控与日志生产环境没有监控等于裸奔。我用PrometheusGrafana来监控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(directorytemplates, auto_reloadFalse)启用Gzip压缩from fastapi.middleware.gzip import GZipMiddleware app.add_middleware(GZipMiddleware, minimum_size1000)调整Uvicorn工作进程数CPU核心数×21uvicorn 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返回时间不一致。统一用UTCfrom datetime import datetime, timezone def get_current_time(): return datetime.now(timezone.utc)内存泄漏原来是忘了配置UVICORN的日志级别。在启动命令加个参数uvicorn main:app --log-level warning

更多文章