Flask自带的app.run()或flask run绝对不能用于生产环境,因其单线程阻塞模型导致请求排队、无超时控制、易受慢速攻击,且崩溃即全挂;而Gunicorn通过多worker隔离实现高可用与自动恢复。

Flask自带的app.run()或flask run绝对不能用于生产环境——这不是“不够好”,而是设计上就拒绝承担生产职责。
单线程阻塞模型会让整个服务瞬间瘫痪
开发服务器默认是同步、单线程的,一个请求卡住(比如数据库慢查询、第三方API超时、未设timeout的requests.get()),后续所有请求就排队干等。没有超时控制,没有中断机制,恶意慢速攻击(如Slowloris)几条连接就能让它彻底不可用。
- 现象:
curl http://your-server/卡住十几秒不动,其他用户全部 504 Gateway Timeout - 根本原因:
app.run()底层用的是Werkzeug的make_server(),不支持worker隔离,崩溃即全挂 - 对比:Gunicorn每个
worker进程相互独立,一个崩溃不影响其余,主进程自动拉起新worker
ImportError: cannot import name 'app' 是路径没对齐,不是代码写错了
执行gunicorn myapp:app报这个错,90%是因为Python找不到模块。它不是语法错误,而是导入上下文错了。
-
myapp必须是可导入的包(含__init__.py),不能只是myapp.py文件 -
app必须是模块顶层的全局变量,不能藏在函数里、类方法里,也不能被if __name__ == '__main__':包裹 - 当前工作目录得在
myapp的父目录下,否则python -c "import myapp"都失败 - 虚拟环境必须激活,且
gunicorn和你的应用依赖安装在同一环境里
--workers 数不是越多越好,CPU核数和IO类型决定上限
盲目套用workers = multiprocessing.cpu_count() * 2 + 1容易翻车。实际要分场景看:
立即学习“Python免费学习笔记(深入)”;
- CPU密集型(如图像处理、加密计算):worker数接近物理核数,再多反而因GIL切换拖慢整体
- IO密集型(如调HTTP、查数据库):可以适当提高,但得配好数据库连接池(比如SQLAlchemy的
pool_size),否则OperationalError: too many connections - 内存受限时:每个worker独占一份内存镜像,
ps aux | grep gunicorn看RSS值,OOM前就该降worker - 开发机别设太高:2核机器跑
--workers 10,上下文切换开销反而压低吞吐
跳过Nginx直连Gunicorn,等于裸奔上线
很多人以为gunicorn -b 0.0.0.0:8000跑起来就能对外服务,其实立刻暴露三个硬伤:
- 静态文件全扔给Flask处理:
/static/js/app.js这种请求也走Python,白白消耗worker - 大请求体(如上传10MB文件)可能触发
ConnectionResetError——Gunicorn没缓冲,Nginx的client_max_body_size和proxy_buffer能兜底 - HTTPS解密必须由前端做:TLS终止不在Gunicorn层,直接暴露HTTP端口风险极高
真正上线时,Gunicorn只监听127.0.0.1:8000或unix socket,Nginx做反向代理、静态服务、SSL终止——少一个环节,线上就多一分不稳定。


















