V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
sadfQED2
V2EX  ›  Python

Python Web 项目的部署如此之复杂!

  •  
  •   sadfQED2 · 2023-12-12 20:23:18 +08:00 · 3378 次点击
    这是一个创建于 379 天前的主题,其中的信息可能已经有所发展或是发生改变。

    接手了一个 python django 写的上古项目。今天稍稍改了改,部署上线的时候突然看到启动命令竟然写的是python manage.py runserver

    虽然我从来没写过 django 项目,但是我也知道这命令启动的是开发测试服务器。就跟前端的npm run dev一样。此时我内心”这特么怎么行,线上业务啊,怎么能这么敷衍,跑个测试服务器就上线“。于是想着改改 Dockerfile ,改成正经的线上部署。

    可是我也没搞过 django 啊,经过一通搜索,大致了解到,django 可以通过 Gunicon 、uWSGI 、Apache mod_wsgi 、Daphne 、Hypercom 、Uvicom 等等方式部署。我淦,怎么这么多啊,我也不知道选哪个啊,uWSGI 在官网写在第一个的,那就他吧。

    照着官网示例抄吧,先这样再那样,Dockerfile 改好了,试一试,草,Docker 容器怎么启动就停了?一通排查,原来 uwsgi --ini uwsgi.ini这命令不是前台运行的,Dockerfile 里面拿这个当启动命令起来立马就没了。

    经过 N 久翻阅文档,发现 uwsgi 启动会生成一个 pid 文件,看到这里,我这个大聪明有办法了,于是 Dockerfile 启动命令改成CMD uwsgi --ini uwsgi.ini && tail -f uwsgi.pid ,再次尝试,容器成功保活。

    正在得意我的聪明才智的时候,结果一看,我淦,uwsgi 是起来了,但是服务为啥不能用啊。又一通排查,我淦,uwsgi.ini 里面的路径好像有问题,可这玩意路径写到哪里文档也没说啊,网上一会说是项目路径,一会说是 app 路径,什么鬼啊,一个一个尝试,结果都特么不行。

    再仔细翻翻文档,这什么玩意呀,部署上线什么还要带个 sqllite 文件呀,怎么还有先执行命令整理代码啊,怎么还要。。。。。

    从早上 10 点一直捣鼓到现在晚上 8 点,饭都没吃饱,这什么破玩意啊。md 果断敲下 git reset -hard 。滚 tm 的,我真是吃饱了没事干,服务跑得好好的,改什么改,前人用开发服务器肯定是有他的道理的,瞎改什么改。就算服务挂了,Docker 容器自动拉起,有毛线关系啊。

    不得不感叹,我部署过上古时期的 java 项目,拷个 war 包上线。也部署过 php 项目,拷份代码到目录就上线,也部署过 golang 项目,本地交叉编译拷个二进制文件上线,也部署过 c c++项目... 像 python 这么恶心的还是第一次,什么乱七八糟路径,调试又没日志,找到日志又不清不楚的,没人用这玩意果然是有原因的。

    43 条回复    2024-02-06 11:27:57 +08:00
    yakun4566
        1
    yakun4566  
       2023-12-12 20:37:55 +08:00
    python *.py 还好吧,我们线上项目 Java 也是 java -jar 啊(也有可能是我们水分太大
    volvo007
        2
    volvo007  
       2023-12-12 23:09:16 +08:00
    op 好惨,上来选了个最“基础” 的…… 选 gunicorn 可破,但是,光选中间件也不行啊,你还没部署 nginx 反向代理呢 (狗头
    shimada666
        3
    shimada666  
       2023-12-13 00:31:57 +08:00   ❤️ 2
    搞那么麻烦干嘛,直接 python manage.py runserver 就好了。
    等 qps 过 20 再考虑别的吧
    arischow
        4
    arischow  
       2023-12-13 08:43:24 +08:00 via iPhone   ❤️ 7
    你接手的代码烂,你也菜😄
    llsquaer
        5
    llsquaer  
       2023-12-13 09:30:07 +08:00
    写的 api 接口,直接 python manage.py runserver 没毛病。。工作期间 8 小时内 平均 QPS 80 左右至今没问题。内部使用。

    不过 python web 是略显复杂。主要就几个容器的区别。熟悉一个当万金油用
    sadfQED2
        6
    sadfQED2  
    OP
       2023-12-13 09:48:05 +08:00 via Android
    @shimada666 线上大几十台机器,你说 qps 过 20 不

    @llsquaer 直接 runserver 区别大吗?是一个 ai 模型,为了提供 api 调用,就 django 包了一层,整个项目就一个接口,代码不超过 100 行
    ihmily
        7
    ihmily  
       2023-12-13 09:58:44 +08:00
    项目就一个接口,直接使用 fastapi 就好了
    JiaNa
        8
    JiaNa  
       2023-12-13 10:02:41 +08:00 via iPhone
    @sadfQED2 既然你说了是旧项目,如果之前没有出现性能问题,那么没有性能问题。
    如果你愿意折腾、学东西,模拟生产环境 API 进行压测,比较不同方式的性能区别。
    shimada666
        9
    shimada666  
       2023-12-13 10:08:50 +08:00
    @sadfQED2 完全没问题,容器挂个 restart=always ,崩了还能重新启动
    sadfQED2
        10
    sadfQED2  
    OP
       2023-12-13 10:12:17 +08:00
    @JiaNa 线上服务,不能随便压。我也不是专业运维,也不是专业的 python 开发。但是就我的理解,直接 python runserver 这应该是单进程运行的,就 python 来说这应该完全没办法充分利用 cpu 。

    但是这个项目本质上是调用 PyTorch ,PyTorch 底层又是调用 C++模块,C++模块是不是就能不受限于 Pyton 的单进程直接跑满 CPU 了我也不清楚。

    所以到底能不能充分利用 cpu 我也搞不清楚。
    sadfQED2
        11
    sadfQED2  
    OP
       2023-12-13 10:14:30 +08:00
    @shimada666 #9 现在容器就是 restart=always ,然后上层网关配置了故障转移。某次请求失败会自动转到其他机房的容器上。但是想着 python runserver 还监听代码变化,随时重启,心里就觉得不舒服
    RedisMasterNode
        12
    RedisMasterNode  
       2023-12-13 10:16:35 +08:00
    感觉不是语言的问题。不太理解,这些东西不是在 README 里面写好就行了吗?

    https://images2.imgbox.com/91/09/qF1P6Xv1_o.png

    这是自己写的古老的新人项目,入职第一周做的,要怎么运行写好就是了,python 也是一样的。

    所以骂 python 没用,python 也有一样轻轻松松启动的项目,要怪就怪你这个同事。我运行 java 项目也摸索了很久不知道要怎么启动,c++ 也是各种依赖问题,说白了就是还菜(没有贬义,每个人都有新学东西的时候),还没入门,接手了不熟悉的语言就要运行要调试了,心态放好点都不至于这样。
    chenqh
        13
    chenqh  
       2023-12-13 10:18:52 +08:00
    因为 python 有 gil,所以 djanog runserver 就可以了啊,gunicorn 用进程模型的话,就相当于 master 负责起多个进程
    chenqh
        14
    chenqh  
       2023-12-13 10:20:31 +08:00
    python 像 tornado 想要利用多核,就是 supervisor 起多个进程,模型更简单粗暴
    wizardyhnr
        15
    wizardyhnr  
       2023-12-13 10:30:10 +08:00
    uwsgi+nginx+django 部署本来就是配置多个服务,这种多进程通信 debug 就很难了。楼主还选 docker 容器,docker 推荐一个容器一个服务,一个容器部署多个服务可能很多坑。楼主属于踩坑体质吧?
    msg7086
        16
    msg7086  
       2023-12-13 10:42:02 +08:00
    下次你试试看部署一下那种 2000 年前后写的带汇编的 C 项目到现代的平台。才折腾一天叫什么复杂。
    光是把内嵌的 MMX 和 3dnow!汇编全部重写成 SSE/AVX 就得花掉你几星期(笑)
    biaodianfu
        17
    biaodianfu  
       2023-12-13 11:36:41 +08:00   ❤️ 1
    Django 没接触,不知道怎么部署还情有可原,Linux 命令也不熟悉,才得意自己的聪明才智,即使不知道使用 supervisor 守护进程,也应该知道使用 nohup 命令让程序不挂起。
    wenrouxiaozhu
        18
    wenrouxiaozhu  
       2023-12-13 11:42:16 +08:00
    @sadfQED2 用 Gunicon 吧👀...觉得“runserver 监听代码变化,随时重启,心里就觉得不舒服” ,可以后面加一个--noreload 😂
    elboble
        19
    elboble  
       2023-12-13 13:42:07 +08:00
    是略烦,反正 supervisor+uwsgi+nginx+django ,搞过一次就行了,路径什么的,的确文档说的不清楚,每次都是对着原来的例子改的。
    dayeye2006199
        20
    dayeye2006199  
       2023-12-13 13:53:23 +08:00
    chatgpt 糊个 dockerfile 很快的
    tfdetang
        21
    tfdetang  
       2023-12-13 14:10:13 +08:00
    @sadfQED2 ai 模型直接 runserver 会阻塞吧,并发请求还是会有问题的;
    如果这种场景最好还是用 fastapi ; 可以找个 uvicorn + fastapi + docker 的模板项目改改就行了;
    当然现在这样也不是不能用
    sadfQED2
        22
    sadfQED2  
    OP
       2023-12-13 15:25:43 +08:00 via Android
    @tfdetang 啊?会阻塞吗?我等会试试,现在一次推理也就十多二十毫秒,可能机器够多,负载均衡后一直没发现问题

    fastapi 能简单一点?你别忽悠我,我部署这玩意已经恶心吐了,换一个等会我又几天搞不出来。主要是这破玩意还要 GPU ,然后走公司部署系统又必须要 Dockerfile ,在 docker 里面搞显卡驱动 cuda 啥的我已经吐了
    sadfQED2
        23
    sadfQED2  
    OP
       2023-12-13 15:34:24 +08:00 via Android
    @tfdetang 我测试了一下,不会阻筛,两个请求是并行的
    nevermoreluo
        24
    nevermoreluo  
       2023-12-13 16:41:02 +08:00
    哈哈哈哈哈 确实挺复杂的
    去年闲时捡起了很多年前 python ,随便折腾也折腾了一下午 docker+uwsgi+django
    https://github.com/nevermoreluo/kitchen/blob/main/docker-compose.yml
    祝你好运吧
    chenqh
        25
    chenqh  
       2023-12-13 18:06:18 +08:00
    @sadfQED2 汗了,django 单进程,同步肯定阻塞啊,你不信,就去 sleep 看一下,就知道了,一般而已 python 要部署多个实例,
    在 docker 之前就是用 supervisor 起多个进程, docker 时代应该是起多个实例
    sadfQED2
        26
    sadfQED2  
    OP
       2023-12-13 18:38:55 +08:00 via Android
    @chenqh 我就是 sleep 测试的,sleep10 秒,同时发两个请求,两个都 10s 后正常返回
    chenqh
        27
    chenqh  
       2023-12-13 18:41:32 +08:00
    @sadfQED2 你不会是起了多个 docker 实例吧,还是说我的理解有问题?
    sadfQED2
        28
    sadfQED2  
    OP
       2023-12-13 18:47:02 +08:00
    @chenqh #27
    ```
    re_path("sleep",data.sleep)

    def sleep(request):
    time.sleep(10)
    return HttpResponse(json.dumps({
    "status": 1,
    }))
    ```

    python manage.py runserver 启动

    开 2 个命令行,同时 curl 127.0.0.1:8000/sleep ,两个请求都是 10s 后同时返回
    chenqh
        29
    chenqh  
       2023-12-13 18:59:17 +08:00   ❤️ 1
    chenqh
        30
    chenqh  
       2023-12-13 18:59:37 +08:00
    @sadfQED2 我的,我用 tornado 来理解 django 了
    KJR5OR04CnCiWf02
        31
    KJR5OR04CnCiWf02  
       2023-12-13 20:56:00 +08:00
    楼主在做什么 ai 应用?感觉是个大怨种。
    XxxxD
        32
    XxxxD  
       2023-12-13 21:19:15 +08:00
    uwsgi 文档感觉好久都没更新,可以 youtube 搜下搭配 Gunicorn 部署
    fantathat
        33
    fantathat  
       2023-12-13 22:16:56 +08:00
    确实复杂,用 gunicorn 涉及到 wsgi, 需要导出 application?
    iorilu
        34
    iorilu  
       2023-12-14 07:40:33 +08:00
    生成环境不要设折腾, 只要能跑就不要动
    IurNusRay
        35
    IurNusRay  
       2023-12-14 09:46:27 +08:00
    你的 uwsgi.ini 文件是不是配置了 daemonize , 这种模式 uwsgi 主进程开启子进程后会退出,于是 docker 容器也会停止,改成 logto 就可以
    tfdetang
        36
    tfdetang  
       2023-12-14 09:51:42 +08:00
    @sadfQED2 看来 django 默认开启了多线程; 其实 docker 里不用搞显卡驱动啥的,base 镜像直接用 torch 啥的官方 gpu 版本的镜像,后面只要把 python 的部分搞定就行了
    sanzrolee
        37
    sanzrolee  
       2023-12-14 09:52:24 +08:00
    uvicom + supervisor 嘎嘎香,再套层 docker 容器在最外层也可以。
    julyclyde
        38
    julyclyde  
       2023-12-15 19:14:34 +08:00
    uwsgi 难道没有“前台运行”功能吗?
    干嘛用 tail 来保活?

    那你用了 tail ,将来运行 docker kill 的时候,你让 tail 命令去被 kill 么?
    julyclyde
        39
    julyclyde  
       2023-12-15 19:15:50 +08:00
    你想要的那种“只上传应用程序本身,但是不管运行机制”其实在 python 世界也是存在的
    就是 google appengine 、sina appengine 、heroku 那一类

    python 、nodejs 、java 比较像,都是“由该语言本身写一个服务器”来运行自己
    julyclyde
        40
    julyclyde  
       2023-12-15 19:16:25 +08:00
    还有,如果你们的数据库是 sqlite ,将来可能扩容到多实例的时候会遇到问题
    julyclyde
        41
    julyclyde  
       2023-12-15 19:19:47 +08:00
    @sadfQED2 大几十台机器不一定过 20 啊
    你知道不,东南亚某知名电子商务网站,在 99 大促销的时候,曾经有关键组件“高达四十八 QPS”,比平时翻两番呢

    你 AI 模型的运行速度,浏览器能等得了么?回头估计还得加个 celery
    Maerd
        42
    Maerd  
       2023-12-20 11:36:46 +08:00
    比较好奇 一个接口为什么要用 django,而不是用更方便的 fastapi
    Xs2y6914BljWqNfl
        43
    Xs2y6914BljWqNfl  
       324 天前
    @Maerd 完全看个人喜好的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3294 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 33ms · UTC 11:52 · PVG 19:52 · LAX 03:52 · JFK 06:52
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.