2009-08-18 40 views
16

我正在研究一些基于Apache的MPM prefork服务器的Python代码。我更像是一个应用程序员,而不是网络程序员,从我读史蒂文斯已经有10年了,所以我正在努力加快理解代码。accept()与在多个进程之间共享的套接字(基于Apache预执行)

我发现了how Apache's prefork code works, by Sander Temme的简短说明。

通常以root身份运行的父进程绑定到套接字 (通常是端口80或443)。它产生子代,继承套接字的开放 文件描述符,并将uid和gid更改为非特权用户和组。孩子们构造了监听器文件描述符(如果有多个监听器) 的轮询集 并监视其上的活动。如果找到活动,孩子在活动套接字上调用 accept()并处理连接。当它与 完成时,它返回到观看pollset(或听众文件 描述符)。

由于多个子项都处于活动状态,并且它们都继承了相同的套接字文件描述符,所以它们将观察同一个pollset。 一个接受互斥体只允许一个孩子实际观看民意调查组, ,一旦发现一个活动的套接字,它将解锁互斥体,所以 下一个孩子可以开始观看民意调查组。如果只有一个 侦听器,则不会使用接受互斥量,并且所有子级都将在 accept()中挂起。

这几乎是我看到的代码的工作方式,但我不明白一些事情。

1)“孩子”和“听众”之间有什么区别?我认为每个孩子都是一个听众,这对我所看到的代码来说是真实的,但在Temme的描述中,可以有“单一的听众”和“孩子”。孩子什么时候会有多个听众?

2)(与1相关)这是每进程互斥锁还是系统互斥锁?对于这个问题,为什么有一个互斥体?不接受(2)对所有听众都做自己的互斥吗?我的研究表明,我确实需要一个互斥体,并且互斥体必须贯穿整个系统。 (羊群,旗语等)

Temme接着说:在共享内存 区(记分牌)

儿童纪录,当他们最后 服务的请求。空闲的孩子可能会被 父母程序杀死,致 满足MaxSpareServers。如果太少, 孩子空闲,父母会 产卵孩子满足 MinSpareServers。

3)是否有一个很好的参考代码(最好在Python中)?我发现Perl的Net::Server::Prefork,它使用管道而不是共享内存作为记分板。我发现了一篇Randal Schwartz的文章,它只执行preforking,但没有记分牌。

pre-fork example from the Perl Cookbook没有任何类型的锁定选择,Chris Siebenmann's Python example表示它基于Apache,但为记分板使用配对套接字,而不是共享内存,并使用套接字控件,将给定子控件包含到'接受。这完全不符合Apache描述。

+0

你是否使用'mod_wsgi'作为Apache和Python之间的接口?如果是这样,它应该为你处理所有这些。 – 2009-08-18 13:04:02

+0

这是一个纯Python预执行WSGI服务器。我的客户希望为不需要Apache和mod_wsgi的地方提供轻量级解决方案,或者同等的解决方案。我找到的唯一一个只有Python的WSGI服务器是Spawning,它需要eventlet。 ......虽然现在我发现flup有一个像Siebenmann's的实现,它使用记分板的管道而不是共享内存,并且具有可接受的许可证给我的客户端。 – 2009-08-18 13:23:13

回答

15

就(1)而言,监听器仅仅是对接受连接的套接字的存在的引用。由于Apache可以同时接受多个套接字上的连接,例如,80/443,因此有多个侦听套接字。每个子进程都需要在所有这些套接字上进行监听。由于accept()一次只能在一个套接字上完成,因此它在poll/select之前,因此知道应在哪个侦听器套接字上执行接受。

关于(2),它是一个全局或跨进程互斥体。也就是说,锁定它的一个进程将阻止尝试获取相同锁的其他进程。尽管accept()在技术上将序列化进程,但是多个侦听器套接字的存在意味着你不能依赖它,因为你不知道在哪个套接字上执行接受。即使在单个侦听器套接字的情况下,接受互斥锁的原因是,如果有大量进程处理请求,则操作系统唤醒所有进程以查看哪些接受了accept()返回,这可能会非常昂贵。由于Apache在prefork模式下可能有100多个进程,这可能会导致问题。因此,如果你只有一个监听套接字,并且知道你只有几个进程想要执行accept()调用,那么你可能会取消跨进程接受互斥体。

+0

谢谢格雷厄姆!我完全没有想过如何能有多个听众,以及这将如何影响一切。我的理解现在更清晰了,无论是为什么我使用的代码有效,为什么它看起来没有用。 – 2009-10-19 15:40:29

相关问题