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

2016-04-14 11:13:29 +08:00
 2225377fjs

对于 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

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

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

据说并发大了,你 master 进程连 fd 都分发不过来。
micyng
2016-04-14 13:38:02 +08:00
gunicorn 没记错的话也是子进程共享的模式
peter999
2016-04-14 13:38:16 +08:00
用 python 的 github 上找得到的轮子我都不想自己撸
msg7086
2016-04-14 13:43:07 +08:00
如果你不需要支持 Windows 的话,直接让一堆进程监听同一个端口不就行了吗。
maemual
2016-04-14 13:44:18 +08:00
@2225377fjs 正常 Python 单机多实例部署的时候,也都是前面有一层 Gunicorn/uWSGI 来实现的,实现你说的各种功能。。。。
2225377fjs
2016-04-14 14:05:21 +08:00
@BOYPT 囧,我也发现了,表达能力有限,当年读书的时候没有好好学语文。。。
2225377fjs
2016-04-14 14:07:56 +08:00
@est 还好吧,暂时没有遇到过这种极端的情况,因为我们生产环境机器相对好一些?一个监听进程,然后多开几个 worker 进程,简单的 ab 测试 http 请求, 2W 的 qps 的时候好像也没有出过这种情况,也还好,暂时没有测试过单个监听进程 accept 和 sendmsg 的极限吞吐量,反正肯定足够用了。
2225377fjs
2016-04-14 14:10:14 +08:00
@micyng 如果是 nginx 那种方式来实现进程间共享监听的话,可能确实不错,但是如果不加改造,简单的启动多个 python 进程共享同一个监听的话,会发现大多数的连接都被同一个进程拿到了,对于短连接可能还好,但是对于长连接的 TCP 服务的话应该是不能容忍的。
vincenttone
2016-04-14 14:13:27 +08:00
启动一个主进程,先建立一个 socket ,然后 fork ,用子进程去 accept ,子进程加锁,拿到锁的可以 accept 。
2225377fjs
2016-04-14 14:17:05 +08:00
@maemual 对于现在 python 开发 web 的部署方式不是很熟,毕竟这个 http 只是附带的功能。主要是用来实现将 tcp 连接相对比较均匀的分散到 worker 进程上面去,然后 worker 可以自己确定是否还要接收 tcp 连接,如果达到 worker 的阈值的话, worker 可以断开与监听进程的连接来,等以后负载降下来了再自己连上去。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/270965

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX