对于 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 系统的时候,只监听一个端口,然后可以方便的扩展出一些负载均衡的功能。
1
zhicheng 2016-04-14 11:50:37 +08:00
监听进程将接收到的 **文件描述符** 通过 sendmsg 方法发送给 worker 进程
|
2
gkiwi 2016-04-14 12:06:40 +08:00
用的第二种方法。。打算在多服务器时候,做一个类似 nginx 的路由系统,,,
|
3
clino 2016-04-14 12:11:52 +08:00 via Android
用 uwsgi 不就好了 你要的功能它都有
|
4
9hills 2016-04-14 12:13:58 +08:00
人生苦短,我用 Python
人生苦太短,我用 Gunicorn 没必要重复造轮子 |
5
maemual 2016-04-14 12:27:54 +08:00
说了半天不就是 Gunicorn/uWSGI 么。。。
|
6
2225377fjs OP @maemual 额,不太清楚 Gunicorn/uWSGI ,没有用过,最开始是用在 Tcp 服务的,因为需要将客户端的连接分散在多个 gate 进程上,而且有一些负载均衡的处理,这样子做会相对比较方便,后来自己把它也搞到了 Http 的部分, worker 用的是 gevent 的 wsgi server , tornado 的 webapplication ,这样子所有进程都可以同一个 python 入口启动,好像用起来还可以,吞吐量什么的都还 ok 。
|
7
2225377fjs OP @9hills 哈哈,也是逼不得已,不然也不想造这玩意的。
|
8
c4pt0r 2016-04-14 13:22:08 +08:00
你这个就是 wsgi
|
9
micyng 2016-04-14 13:32:53 +08:00 via Android
更像 fastcgi ,部署很蛋疼
子进程共享描述符有啥不好了? |
10
BOYPT 2016-04-14 13:35:11 +08:00
发现帖子里面有 4 个“对。。。而言”
|
11
est 2016-04-14 13:36:23 +08:00
> 监听进程将接收到的文件描述符通过 sendmsg 方法发送给 worker 进程
据说并发大了,你 master 进程连 fd 都分发不过来。 |
12
micyng 2016-04-14 13:38:02 +08:00 via Android
gunicorn 没记错的话也是子进程共享的模式
|
13
peter999 2016-04-14 13:38:16 +08:00
用 python 的 github 上找得到的轮子我都不想自己撸
|
14
msg7086 2016-04-14 13:43:07 +08:00
如果你不需要支持 Windows 的话,直接让一堆进程监听同一个端口不就行了吗。
|
15
maemual 2016-04-14 13:44:18 +08:00
@2225377fjs 正常 Python 单机多实例部署的时候,也都是前面有一层 Gunicorn/uWSGI 来实现的,实现你说的各种功能。。。。
|
16
2225377fjs OP @BOYPT 囧,我也发现了,表达能力有限,当年读书的时候没有好好学语文。。。
|
17
2225377fjs OP @est 还好吧,暂时没有遇到过这种极端的情况,因为我们生产环境机器相对好一些?一个监听进程,然后多开几个 worker 进程,简单的 ab 测试 http 请求, 2W 的 qps 的时候好像也没有出过这种情况,也还好,暂时没有测试过单个监听进程 accept 和 sendmsg 的极限吞吐量,反正肯定足够用了。
|
18
2225377fjs OP @micyng 如果是 nginx 那种方式来实现进程间共享监听的话,可能确实不错,但是如果不加改造,简单的启动多个 python 进程共享同一个监听的话,会发现大多数的连接都被同一个进程拿到了,对于短连接可能还好,但是对于长连接的 TCP 服务的话应该是不能容忍的。
|
19
vincenttone 2016-04-14 14:13:27 +08:00
启动一个主进程,先建立一个 socket ,然后 fork ,用子进程去 accept ,子进程加锁,拿到锁的可以 accept 。
|
20
2225377fjs OP @maemual 对于现在 python 开发 web 的部署方式不是很熟,毕竟这个 http 只是附带的功能。主要是用来实现将 tcp 连接相对比较均匀的分散到 worker 进程上面去,然后 worker 可以自己确定是否还要接收 tcp 连接,如果达到 worker 的阈值的话, worker 可以断开与监听进程的连接来,等以后负载降下来了再自己连上去。
|
21
micyng 2016-04-14 14:30:22 +08:00 via Android
@2225377fjs 你现在说的这些东西其实 Nginx 已经成熟地支持了
另外子进程共享的方式,操作系统会处理好 accept 分发的事 还有如果特别针对多进程环境下 TCP 长连接的情况,大可不必担心,因为这种模型不会用于推送的场景,而是处理较大流数据的上传下载业务,用一段时间就关了,跟一个 http 请求其实没什么两样 换做推送场景的话,也不会用多进程模型了,而是得考虑分布式节点了 |
22
micyng 2016-04-14 14:34:42 +08:00 via Android
@2225377fjs 你现在说的这些东西其实 Nginx 已经成熟地支持了
另外子进程共享的方式,操作系统会处理好 accept 分发的事 还有如果特别针对多进程环境下 TCP 长连接的情况,大可不必担心,因为这种模型不会用于推送的场景,而是处理较大流数据的上传下载业务,用一段时间就关了,跟一个 http 请求其实没什么两样 换做推送场景的话,也不会用多进程模型了,而是得考虑分布式节点了 |
23
micyng 2016-04-14 14:37:43 +08:00 via Android
我的 1%被识别成安卓猴了😈
|
24
wuyadong 2016-04-14 15:55:11 +08:00
uwsgi
|
25
clino 2016-04-14 16:48:46 +08:00
@2225377fjs uwsgi 也支持 gevent 和 virtualenv 的
可以自身作为 http server,也可以用自定义的 socket 协议和 nginx 交互,当然自身作为 http server 再被 nginx 反代也行 |
26
tomZhao 2016-04-16 23:06:22 +08:00
一般而言,会使用 gunicorn/uwsgi 做 server 来处理也就是你说的第二种。老实说,我比较不喜欢这种方式,
使用 supervisord 来启动多进程,监听多个端口, nginx 反向代理,则是第一种方式,也可以。我比较喜欢。可以做一些小的优化,比如 cpu 绑定之类的。 |