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
2225377fjs
V2EX  ›  Python

一种比较别扭的 python 多进程 HTTP 服务实现方式,大家觉得如何。?

  •  
  •   2225377fjs · 2016-04-14 11:13:29 +08:00 · 5477 次点击
    这是一个创建于 2940 天前的主题,其中的信息可能已经有所发展或是发生改变。

    对于 Python 而言,在线上部署 HTTP 服务的时候,一般都是采用多进程的方式来做的,毕竟没有 Java 的并行多线程,所以常规的方式是前面通过一个 Nginx 来做反向代理,后端启动多个 Python 进程,监听多个端口。(当然还有一种方式是通过子进程共享 listen 文件描述符来实现,但是这种方式对于 Python 而言会有一些不好的问题)

    在 linux 下还有另外一种实现方式,因为有 sendmsg 和 recvmsg 两个方法: 通过启动一个进程,专门来做 tcp 的监听,然后启动多个进程来做 worker ,通过 Unix 域 socket 与监听进程建立连接,监听进程将接收到的文件描述符通过 sendmsg 方法发送给 worker 进程,然后 worker 进程将文件描述符放入自己的 IOLoop ,当做一个正常的 Tcp 连接处理就好了。。。

    这种方式的优点: 对于 http 服务器而言,少了一个反向代理的过程,本身 nginx 那部分 http 解析的过程可以省掉一些 CPU ,而且对于 python 进程而言部署相对方便一些,不用去设置多个端口。 缺点: 只支持物理单服务器,不可能扩展到多个物理服务器,不支持 Windows , python 本身 socket 不带有 sendmsg API ,需要些 C 扩展。

    其实这个功能最开始是为了做 Tcp 服务器搞的,在架设 gate 系统的时候,只监听一个端口,然后可以方便的扩展出一些负载均衡的功能。

    http://blog.csdn.net/fjslovejhl/article/details/50481961

    26 条回复    2016-04-16 23:06:22 +08:00
    zhicheng
        1
    zhicheng  
       2016-04-14 11:50:37 +08:00
    监听进程将接收到的 **文件描述符** 通过 sendmsg 方法发送给 worker 进程
    gkiwi
        2
    gkiwi  
       2016-04-14 12:06:40 +08:00
    用的第二种方法。。打算在多服务器时候,做一个类似 nginx 的路由系统,,,
    clino
        3
    clino  
       2016-04-14 12:11:52 +08:00 via Android
    用 uwsgi 不就好了 你要的功能它都有
    9hills
        4
    9hills  
       2016-04-14 12:13:58 +08:00
    人生苦短,我用 Python
    人生苦太短,我用 Gunicorn

    没必要重复造轮子
    maemual
        5
    maemual  
       2016-04-14 12:27:54 +08:00
    说了半天不就是 Gunicorn/uWSGI 么。。。
    2225377fjs
        6
    2225377fjs  
    OP
       2016-04-14 13:17:17 +08:00
    @maemual 额,不太清楚 Gunicorn/uWSGI ,没有用过,最开始是用在 Tcp 服务的,因为需要将客户端的连接分散在多个 gate 进程上,而且有一些负载均衡的处理,这样子做会相对比较方便,后来自己把它也搞到了 Http 的部分, worker 用的是 gevent 的 wsgi server , tornado 的 webapplication ,这样子所有进程都可以同一个 python 入口启动,好像用起来还可以,吞吐量什么的都还 ok 。
    2225377fjs
        7
    2225377fjs  
    OP
       2016-04-14 13:19:20 +08:00
    @9hills 哈哈,也是逼不得已,不然也不想造这玩意的。
    c4pt0r
        8
    c4pt0r  
       2016-04-14 13:22:08 +08:00
    你这个就是 wsgi
    micyng
        9
    micyng  
       2016-04-14 13:32:53 +08:00 via Android
    更像 fastcgi ,部署很蛋疼
    子进程共享描述符有啥不好了?
    BOYPT
        10
    BOYPT  
       2016-04-14 13:35:11 +08:00
    发现帖子里面有 4 个“对。。。而言”
    est
        11
    est  
       2016-04-14 13:36:23 +08:00
    > 监听进程将接收到的文件描述符通过 sendmsg 方法发送给 worker 进程

    据说并发大了,你 master 进程连 fd 都分发不过来。
    micyng
        12
    micyng  
       2016-04-14 13:38:02 +08:00 via Android
    gunicorn 没记错的话也是子进程共享的模式
    peter999
        13
    peter999  
       2016-04-14 13:38:16 +08:00
    用 python 的 github 上找得到的轮子我都不想自己撸
    msg7086
        14
    msg7086  
       2016-04-14 13:43:07 +08:00
    如果你不需要支持 Windows 的话,直接让一堆进程监听同一个端口不就行了吗。
    maemual
        15
    maemual  
       2016-04-14 13:44:18 +08:00
    @2225377fjs 正常 Python 单机多实例部署的时候,也都是前面有一层 Gunicorn/uWSGI 来实现的,实现你说的各种功能。。。。
    2225377fjs
        16
    2225377fjs  
    OP
       2016-04-14 14:05:21 +08:00
    @BOYPT 囧,我也发现了,表达能力有限,当年读书的时候没有好好学语文。。。
    2225377fjs
        17
    2225377fjs  
    OP
       2016-04-14 14:07:56 +08:00
    @est 还好吧,暂时没有遇到过这种极端的情况,因为我们生产环境机器相对好一些?一个监听进程,然后多开几个 worker 进程,简单的 ab 测试 http 请求, 2W 的 qps 的时候好像也没有出过这种情况,也还好,暂时没有测试过单个监听进程 accept 和 sendmsg 的极限吞吐量,反正肯定足够用了。
    2225377fjs
        18
    2225377fjs  
    OP
       2016-04-14 14:10:14 +08:00
    @micyng 如果是 nginx 那种方式来实现进程间共享监听的话,可能确实不错,但是如果不加改造,简单的启动多个 python 进程共享同一个监听的话,会发现大多数的连接都被同一个进程拿到了,对于短连接可能还好,但是对于长连接的 TCP 服务的话应该是不能容忍的。
    vincenttone
        19
    vincenttone  
       2016-04-14 14:13:27 +08:00
    启动一个主进程,先建立一个 socket ,然后 fork ,用子进程去 accept ,子进程加锁,拿到锁的可以 accept 。
    2225377fjs
        20
    2225377fjs  
    OP
       2016-04-14 14:17:05 +08:00
    @maemual 对于现在 python 开发 web 的部署方式不是很熟,毕竟这个 http 只是附带的功能。主要是用来实现将 tcp 连接相对比较均匀的分散到 worker 进程上面去,然后 worker 可以自己确定是否还要接收 tcp 连接,如果达到 worker 的阈值的话, worker 可以断开与监听进程的连接来,等以后负载降下来了再自己连上去。
    micyng
        21
    micyng  
       2016-04-14 14:30:22 +08:00 via Android
    @2225377fjs 你现在说的这些东西其实 Nginx 已经成熟地支持了
    另外子进程共享的方式,操作系统会处理好 accept 分发的事
    还有如果特别针对多进程环境下 TCP 长连接的情况,大可不必担心,因为这种模型不会用于推送的场景,而是处理较大流数据的上传下载业务,用一段时间就关了,跟一个 http 请求其实没什么两样
    换做推送场景的话,也不会用多进程模型了,而是得考虑分布式节点了
    micyng
        22
    micyng  
       2016-04-14 14:34:42 +08:00 via Android
    @2225377fjs 你现在说的这些东西其实 Nginx 已经成熟地支持了
    另外子进程共享的方式,操作系统会处理好 accept 分发的事
    还有如果特别针对多进程环境下 TCP 长连接的情况,大可不必担心,因为这种模型不会用于推送的场景,而是处理较大流数据的上传下载业务,用一段时间就关了,跟一个 http 请求其实没什么两样
    换做推送场景的话,也不会用多进程模型了,而是得考虑分布式节点了
    micyng
        23
    micyng  
       2016-04-14 14:37:43 +08:00 via Android
    我的 1%被识别成安卓猴了😈
    wuyadong
        24
    wuyadong  
       2016-04-14 15:55:11 +08:00
    uwsgi
    clino
        25
    clino  
       2016-04-14 16:48:46 +08:00
    @2225377fjs uwsgi 也支持 gevent 和 virtualenv 的
    可以自身作为 http server,也可以用自定义的 socket 协议和 nginx 交互,当然自身作为 http server 再被 nginx 反代也行
    tomZhao
        26
    tomZhao  
       2016-04-16 23:06:22 +08:00
    一般而言,会使用 gunicorn/uwsgi 做 server 来处理也就是你说的第二种。老实说,我比较不喜欢这种方式,
    使用 supervisord 来启动多进程,监听多个端口, nginx 反向代理,则是第一种方式,也可以。我比较喜欢。可以做一些小的优化,比如 cpu 绑定之类的。
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1006 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 23:42 · PVG 07:42 · LAX 16:42 · JFK 19:42
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.