通常我的服务器上都会启用多个php-cgi程序,有时候这样做是很必要的
1. 可以同时让多个进程处理请求,负载均衡。
2. 避免一个进程崩溃时,在重新启动前,无法及时提供服务。
启用多个相同服务进程必然需要考虑共用一个socket。对于php-cgi程序来说,是通过stdin文件描述符来传递这个socket。
下面是一个示例代码,演示如何启动多个子进程监听同一个端口。
Parent Proecess:
import os, socket, sys s = socket.socket() s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s.bind(("", 8000)) s.listen(10) for i in xrange(3): pid = os.fork() if pid == 0: os.dup2(s.fileno(), sys.stdin.fileno()) os.execv("/usr/bin/python", ("python", "child.py")) else: print "fork", i, "process id =", pid print "Parent exited" sys.exit()
Child Process:
import socket, os, sys print "Child", os.getpid(), "started" s = socket.fromfd(sys.stdin.fileno(), socket.AF_INET, socket.SOCK_STREAM) fd, address = s.accept() print "Accept from", address sys.exit()
执行parent.py后,启动了三个child.py的进程,这三个进程都等待来自8000端口的连接,当有连接时打印对方地址并结束进程。通过终端运行
telnet localhost 8000
可以测试child.py进程的响应。连续telnet三次,则让三个进程都完全结束。
若有更好地方法或者建议,请与我交流 🙂
Haproxy的第四层模式可以参考
Haproxy是个负载均衡的软件吧,你玩这个吗???
可以写规则让相同端口分配负载到不同进程。其实多个进程监听一个端口本质来说也是负载均衡嘛。我用作53端口\(^o^)/~
在哪里编写规则呢?能够写算法如何让不同的进程进行accept?
在HAPROXY中可以写规则,感兴趣的话可以参考一下HAPROXY的文档。如果要实现自己的算法,恐怕要修改一下源代码了
嗯,谢谢!!!
我正需要这玩意,学习一下。
能不能写个C版本的呢?
已经写过了,详见FCGI进程管理器:
http://xiaoxia.org/3646.html
提一点小意见:加强算法和设计模式,并将其付诸实践,这才是王道。其他一切都是浮云,,,
嗯,这个可能是每个软件工程师的基本要求吧!
不过说实话呢,我以后的方向不一定是做软件开发的,所以我自己对算法和模式的要求并不高,只要大部分人能看懂我的代码,能从我的代码学到东西,就很不错啦!
三个进程同时listen同一个端口,那么遇到连接的时候是怎么决定由哪一个进程accept呢?求解
另外,在Linux上的子进程不是可以共享父进程的fd么?为什么要通过stdin去传递呢?
这个处理方式,Linux和Windows好像不同的吧。Linux好像是随机寻找空闲的分配。
为什么要通过stdin去传递呢?因为调用了exec系统调用,已经装载了新的程序,应该只有标准文件描述符被保留下来吧,你觉得呢?
似乎是所有fd都会保留的啊
##########file parent.py ########
from multiprocessing import Process
import os
def info(content):
print content
with fh as f:
print f.readlines()
print ‘process id:’, os.getpid()
def main():
print ‘main line:%s’ %os.getpid()
global fh
fh = open(‘./readme’)
p = Process(target=info, args=(‘child’,))
p.start()
p.join()
if __name__ == ‘__main__’:
main()
###############
output:
main line:4156
child
[‘hello world\n’]
process id: 4157
好像有道理,不过你测试执行exec看看,调用一个不同的程序。
设置了CLOEXEC才会在exec时关闭。。。
也就是说,默认不设置CLOEXEC,在子进程里调用了exec,父进程的文件描述符还是会被保留下来的?
yes
Mike~ 原来你早就知道小虾的新博客地址啊,怎么都不告诉我呢。。。
不是新旧地址都可以访问的吗?
好吧,旧的我也多年没去过了。。。
這個site每日traffic ip系幾多?有1000沒?
no… 200左右ip,怎么了?
那显然上千PV啦
不知道这个怎么算的。
用stdin发送fd?!?把stdin覆盖了呀……
话说,UNIX域套接字发送fd正统一点……
—删— 我以为你是自己写的,原来是fork exec到php进程的。。怪不得。。
把我的想法贴出来(貌似乃用graphviz啊)
digraph G
{
“Request” -> “Daemon”
“Daemon” -> “Service 1″ [label=”fork”]
“Daemon” -> “Service 2″ [label=”fork”]
“Service 1” -> “Subprocess #1″ [label=”same fd”]
“Service 1” -> “Subprocess #2″ [label=”same fd”]
“Service 1” -> “Subprocess #3″ [label=”same fd”]
“Service 2″ -> ” Subprocess #1″ [label=”same fd”]
“Service 2″ -> ” Subprocess #2″ [label=”same fd”]
“Service 2″ -> ” Subprocess #3″ [label=”same fd”]
}
嗯,原来你也用graphviz哦!
这个想法跟我想的差不多啊,我也是有计划写一个Daemon,用它来运行和守护我用python写的一堆服务程序。
unix domain socket还没真正使用过,所以通常都用stdin来传递,没有觉得正统不正统的,只想简简单单点解决问题。
glib有基于UNIX domain socket的send_fd和recv_fd的封装哦~
容易跨平台不?
这是我比较关心的问题。
不要问GLib,你应该问M$,因为POSIX煞费苦心还把AF_UNIX更名为AF_LOCAL了,M$支持不支持?只有它自己知道。
(PS. Windows 7有一个隐藏得很深的POSIX子系统,不过我没测试过。)
恩,这个是学习了fcgi进程管理器的做法,可以spawn php-cgi的进程,也可以让自己写的服务进程也使用这种模式进行工作 🙂
崇拜诸位大牛
是哪位?
看来关键是SO_REUSEADDR 这个参数在起作用啊。。嘿嘿
google搜一个东西,看到头像诧异怎么那么熟悉。。
世界就这么小..