Saturday, September 4, 2010

prefork服务器方式

WEB服务器一般都有两种模式处理动态服务:
1. prefork
2. thread

一种是使用多进程, 另一种是使用多线程.  它们的具体的实现方式自己其实并不清楚.
最近公司的python WEB服务使用较多的内存. 为了清楚其中的问题. 需要学习flup(django需要此库)代码. (  人家写的代码实在好看 )

很多软件都有prefork方式, 下面是prefork模型:

每个nginx子进程都分别调用accept得到用户发来的80端口请求.
之所以每个子进程都可以调用accept得到同一个socket的请求, 是因为fork出的子进程的file descriptor是指向同一个实体.

这样实现了多进程竟争得到socket请求.

每个子进程又可以使用epoll, 线程等方式并发处理众多来自80端口的请求. fast cgi server也是类似的方法.
nginx与fast cgi server之间使用socket通信, 使用fast cgi协议.


每个flup work某一时刻只服务一个页面请求. 完成请求后可以重新接受请求.

使用prefork模型的方式。 所以在PreforkServer类中。

父进程的主体是一个loop:

119         # Main loop.
120         while self._keepGoing:
121             # Maintain minimum number of children.
122             while len(self._children) < self._maxSpare:
123                 if not self._spawnChild(sock): break

可以看出, 父进程是永远期待子进程的数目为一个数值的。这个数值为maxSpare
粗粗看上去, 有些野。但是父进程是有回收子进程的策略的, 如下:

169             # See who and how many children are available.
170             availList = filter(lambda x: x[1]['avail'],
self._children.items())
171             avail = len(availList)

上面的代码可以知道, 父进程会一直收集可用的子进程。 所谓可用是没有在工作
的子进程, 可以从子进程的代码中看出, 如下:
370             # Notify parent we're no longer available.
371             self._notifyParent(parent, '\x00')
372
373             # Do the job.
374             self._jobClass(clientSock, addr, *self._jobArgs).run()

上面的代码是子进程在调用jobClass.run之前, 通知父进程自己是 no longer
available的。


父进程维护着“可用的子进程“数目是为了可以了解负载情况, 判断是否需要产生
更多的子进程, 如下:
172
173             if avail < self._minSpare:
174                 # Need to spawn more children.
175                 while avail < self._minSpare and \
176                       len(self._children) < self._maxChildren:
177                     if not self._spawnChild(sock): break
178                     avail += 1

上面的代码使用了两个数据: minSpare和maxChildren。

minSpare是表示最少“可用子进程“数
maxChildren是表示最大“子进程”数, 是空闲与工作的子进程总数

如果“可用子进程”数还剩一定数据,会被回收, 如下:

179             elif avail > self._maxSpare:
180                 # Too many spares, kill off the extras.
181                 pids = [x[0] for x in availList]
182                 pids.sort()
183                 pids = pids[self._maxSpare:]
184                 for pid in pids:
185                     d = self._children[pid]
186                     d['file'].close()
187                     d['file'] = None
188                     d['avail'] = False

从上面的代码可以看到, fast cgi在启动时的使用到的三个参数的作用应该是:
minspare: 最小“空闲进程数“
maxspare: 常规进程数,即fast cgi启动后, fastcgi进程数是大于等于此值
maxChildren: 最大进程数, 此值主要是用于防止内存被使用完的。

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.