多个进程之间共享套接字的accept()(基于Apache preforking)

发布于 2024-08-02 08:35:34 字数 1812 浏览 1 评论 0原文

我正在研究一些在 Apache 的 MPM prefork 服务器上建模的 Python 代码。我更像是一名应用程序程序员,而不是网络程序员,自从我阅读 Stevens 以来已经有 10 年了,所以我正在努力加快理解代码的速度。

我找到了 Apache 的预分叉代码如何工作,作者:Sander Temme

父进程(通常以 root 身份运行)绑定到套接字 (通常是端口 80 或 443)。它产生孩子,继承开放 套接字的文件描述符,并将 uid 和 gid 更改为 非特权用户和组。孩子们构建了一个民意调查集 侦听器文件描述符的数量(如果有多个侦听器) 并观察其/它们的活动。如果发现活动,孩子会打电话 活动套接字上的accept() 并处理连接。当它是 完成后,它返回观察轮询集(或侦听器文件 描述符)。

由于多个孩子处于活跃状态并且他们都继承了相同的 套接字文件描述符,它们将监视相同的轮询集。 接受互斥体只允许一个孩子实际观看轮询集, 一旦找到一个活动套接字,它将解锁互斥锁,这样 下一个孩子可以开始观看民意调查集。如果只有一个 侦听器,不使用接受互斥锁,所有子级都会挂起 接受()。

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

1)“孩子”和“倾听者”有什么区别?我认为每个孩子都是一个侦听器,这对于我正在查看的代码来说是正确的,但在 Temme 的描述中可以有“单个侦听器”和“孩子”。一个孩子什么时候会有多个听众?

2)(与 1 相关)这是每个进程互斥体还是系统互斥体?就此而言,为什么要有互斥体? Accept(2) 不会在所有侦听器之间执行自己的互斥吗?我的研究表明我确实需要一个互斥体,并且互斥体必须遍及整个系统。 (群体、信号量等)

Temme 继续说道:

孩子们在共享内存中记录 他们最后的区域(记分牌) 送达请求。闲散的孩子可能会 被父进程杀死 满足 MaxSpareServers。如果太少 孩子闲着,家长就闲着 产生孩子来满足 最小备用服务器数。

3)这个实现有没有好的参考代码(最好是Python)?我发现 Perl 的 Net::Server::Prefork,它使用管道代替记分板的共享内存。我找到了 Randal Schwartz 的文章,该文章只进行了预分叉,但不进行分叉记分牌。

Perl Cookbook 中的预分叉示例 没有任何类型的锁定select,Chris Siebenmann 的 Python 示例 表示它基于 Apache,但使用记分板的配对套接字,而不是共享内存,并将套接字用于控件,包括给定子项的控件以接受“a”。这与 Apache 的描述完全不符。

I'm working on some Python code modeled on Apache's MPM prefork server. I am more an applications programmer than a network programmer and it's been 10 years since I read Stevens, so I'm trying to get up to speed in understanding the code.

I found a short description of how Apache's prefork code works, by Sander Temme.

The parent process, which typically runs as root, binds to a socket
(usually port 80 or 443). It spawns children, which inherit the open
file descriptor for the socket, and change uid and gid to the
unprivileged user and group. The children construct a pollset
of the listener file descriptors (if there is more than one listener)
and watch for activity on it/them. If activity is found, the child calls
accept() on the active socket and handles the connection. When it is
done with that, it returns to watching the pollset (or listener file
descriptor).

Since multiple children are active and they all inherited the same
socket file descriptor(s), they will be watching the same pollset.
An accept mutex allows only a single child to actually watch the pollset,
and once that has found an active socket it will unlock the mutex so
the next child can start watching the pollset. If there is only a single
listener, that accept mutex is not used and all children will hang in
accept().

This is pretty much the way the code I'm looking at works, but I don't understand a few things.

1) What is the difference between a "child" and a "listener"? I thought each child is a listener, which is true for the code I'm looking at, but in Temme's description there can be "a single listener" and "children." When would a child have multiple listeners?

2) (Related to 1) Is this a per-process mutex or a system mutex? For that matter, why have a mutex? Doesn't accept(2) do its own mutex across all listeners? My research says I do need a mutex and that the mutex must be across the entire system. (flock, semaphore, etc.)

Temme goes on to say:

Children record in a shared memory
area (the scoreboard) when they last
served a request. Idle children may
be killed by the parent process to
satisfy MaxSpareServers. If too few
children are idle, the parent will
spawn children to satisfy
MinSpareServers.

3) Is there a good reference code for this implementation (preferably in Python)? I found Perl's Net::Server::Prefork, which uses pipes instead of shared memory for the scoreboard. I found an article by Randal Schwartz which only does the preforking but doesn't do the scoreboard.

The pre-fork example from the Perl Cookbook does not have any sort of locking around select, and Chris Siebenmann's Python example says it's based on Apache but uses paired sockets for the scoreboard, not shared memory, and use the sockets for controls, include the control for a given child to 'a'ccept. This does not match the Apache description at all.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

甜`诱少女 2024-08-09 08:35:34

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

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

因此,如果您只有一个侦听器套接字,并且知道只有几个进程想要执行accept()调用,那么您可以取消跨进程accept互斥体。

In respect of (1), the listener is merely a reference to the existence of socket on which to accept connections. Since Apache can accept connections on multiple sockets at the same time, eg., 80/443, then there are multiple listener sockets. Each child process would need to listen on all of these sockets when it comes its time. Since accept() can only be done on one socket at a time, it is preceded by the poll/select so it is known on which listener socket the accept should be performed.

In respect of (2), it is a global or cross process mutex. That is, one process locking it will block out other processes trying to acquire the same lock. Although accept() will technically serialise the processes, the presence of multiple listener sockets means you cannot rely on that as you don't know before hand which socket to perform accept on. Even where a single listener socket, the reason for the accept mutex is that if there are large numbers of processes handling requests, then it could be quite expensive if operating system wakes up all processes to see which then has accept() return for it. Since Apache in prefork mode may have 100+ processes, that could cause a problem.

So, if you have only a single listener socket and know you only have a few processes wanting to do the accept() call then you can possibly do away with the cross process accept mutex.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文