Uvicorn、Gunicorn 傻傻分不清?FastAPI 生产部署避坑指南
摘要:你是不是也遇到过 FastAPI 应用一上量就卡死、502 频发?这篇来自程序媛老友的经验之谈,不讲天书,只给你最落地的 ASGI/WSGI 服务器选型指南、配置参数详解和 Docker、Linux 部署实例。哪怕你只懂一点后端,跟着做也能搞出一个稳建的生产环境。
🎯 开头就是暴击:为什么我的 FastAPI 一上生产就跪?
你有没有过这种崩溃瞬间 —— 笔记本上 uvicorn main:app --reload 跑得行云流水,接口响应快到飞起。
结果兴冲冲部署到服务器,并发量刚一上来,请求就开始排队,然后 502、504 哗啦啦地来,用户群里瞬间炸锅。
别问我怎么知道的,那种滋味,真不想你再尝一遍。
所以今天这篇,我打算把 Uvicorn、Gunicorn 这些名字绕口的家伙,用你最听得懂的方式盘一遍,再给你一套拿来就能用的部署配置。
👩💻我是爱折腾的一名程序媛,喜欢研究全栈开发的各种实践,热爱分享踩坑后的收获与思考,也享受用代码写出各种实用小工具解决问题的快乐。
如果你也在技术这条路上向前走,关注我,愿我们能彼此陪伴,一起成为更好的自己 🌱
📌 本文能帮你解决什么
🔹 搞清楚 Uvicorn、Gunicorn、WSGI、ASGI 到底谁是谁的谁
🔹 知道什么时候用 uvicorn --workers,什么时候必须上 Gunicorn
🔹 拿到生产级 Gunicorn + Uvicorn 的配置样板
🔹 避开端口冲突、超时、僵尸进程等常见大坑
🔹 学会不同环境(开发、Docker、Linux 生产)的部署套路
🧠 核心原理:别把“饭店伙计”当成“饭店老板”
很多人刚接触部署,以为 uvicorn 就是一个完整的 Web Server,其实它更像一个跑得很快的伙计,能端菜(处理请求),但不会管理后厨的人手。
咱们打个比方,你的 FastAPI 应用是一家网红餐厅:
🔹 Uvicorn
是手脚麻利的服务员,接单上菜特别快,尤其是对需要等一会的菜(异步请求),它能先去招呼别桌,不会傻站着。
🔹 Gunicorn
是店长,它自己不端盘子,但它管着一群服务员,规定谁干活、干多少活、干累了换班、出了错重启。
🔹 Nginx
是门口的大堂经理,负责迎客、分流、挡掉捣乱的人。
那 WSGI 和 ASGI 呢?就是服务员和后厨的沟通协议。
🔹 WSGI 是同步的,一次只端一个菜。
🔹 ASGI 是异步的,适合同时处理好几桌的点单,FastAPI 天生就讲 ASGI 语。
好,现在你肯定想问:那 Uvicorn 自己不是也有 --workers 参数吗?直接用不就行了?接下来重点来了。
⚡ 实战对比:直接裸奔 vs 工头带队
🐍 方案一:直接 uvicorn --workers 4
确实,Uvicorn 支持多 worker,但这个“多”是靠它自己 fork 出来的,没有 Gunicorn 那么老练。实际跑起来,你会发现:
🔹 某个 worker 悄悄死掉,它不一定能拉起来。
🔹 内存占用管理比较糙。
🔹 信号处理和优雅关机,偶尔就闹脾气。
这里有一点要特别注意,如果你在 Windows 上开发,--workers 根本不能用!
你只能老老实实开多个进程,用端口转发,巨麻烦。所以 Windows 上只建议跑单 worker 做调试。
🛡️ 方案二:Gunicorn + UvicornWorker(生产首选)
这才是正经的生产之道。用 Gunicorn 来管理多个 Uvicorn worker 进程,每个 worker 依然使用 ASGI 协议,稳得一批。
命令长这样:
gunicorn main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
🔹 -w 4:开 4 个 worker 进程。
🔹 -k uvicorn.workers.UvicornWorker:指定干活的是 Uvicorn 的 worker 类,而不是默认的同步 WSGI worker。
🔹 --bind:监听所有网络接口的 8000 端口。
根据我以往的经验,worker 数设为 CPU 核心数 × 2 + 1 是个比较稳的开局,后期看负载再调。
一味开多,上下文切换反而会拖慢整体。
再说个容易翻车的点:超时时间。
默认 Gunicorn 的 worker 超时只有 30 秒。
如果你的某个接口处理慢,比如生成报表要 1 分钟,那 Gunicorn 会直接杀掉 worker,用户那头就是 502。
务必在启动时加上 --timeout 120 或者更合适的值。
🐳 不同环境的落地姿势
💻 开发环境
追求快和热重载,单进程 Uvicorn 就是最佳答案:
uvicorn main:app --reload --host 0.0.0.0 --port 8000
千万别在 --reload 时加 --workers,你会收获一堆僵尸进程和莫名其妙的文件监控错误。
🚢 Docker 单容器部署
很多人在这里踩坑:容器里起了 Gunicorn,前面要不要再套 Nginx?
如果单机跑,且只在容器内用一个进程,Gunicorn 足够。
但更推荐 Nginx + Gunicorn 分开,用 docker-compose。
Gunicorn 的 --bind 0.0.0.0:8000 后面让 Nginx 做反向代理,处理静态文件和限流。
一个小而美的 Dockerfile 片段:
CMD ["gunicorn", "main:app", "-w", "4", "-k", "uvicorn.workers.UvicornWorker", "--bind", "0.0.0.0:8000"]
🏭 Linux 生产物理机
配合 systemd 或 supervisor 做进程守护,让 Gunicorn 自己做个乖孩子。
把上面那条命令写进启动脚本,让系统帮你盯着,挂了自动拉起来。
🚨 常见翻车现场及抢救
🔹 启动报端口占用:
大概率是上个进程没死干净,lsof -i :8000 查出来 kill 掉。
🔹 静态文件 404:
Gunicorn/Uvicorn 就别伺候静态文件了,丢给 Nginx,性能能翻好几倍。
🔹 WebSocket 连不上:
如果前面套了 Nginx,记得升级 proxy_set_header Upgrade 和 Connection "upgrade" 配置,不然 WebSocket 握手直接断。
🔹 日志里全是 worker timeout:
检查你是不是有个接口偷偷同步调了个耗时的第三方库,把代码改成 async 搭配异步请求库。
💬 最后啰嗦一句
工具的选择上,我认为顺手的才是最好的!Uvicorn + Gunicorn 这对组合我认为是最稳的。
你不用迷信它们,但一定要理解背后“异步处理 + 进程管理”的思想,这样换成 Hypercorn、Daphne 也能一通百通。
把这篇文章保存起来吧,下次半夜被报警电话吵醒的时候,说不定靠这里面的某一句话就能多睡一小时。
如果觉得有用,点赞收藏加个关注,转发给那个还在和 502 死磕的朋友,咱们的技术路,一起少掉两根头发 🎯。
浙公网安备 33010602011771号