Apache 死了;怀疑是 ulimit,但无法重现

Apache 死了;怀疑是 ulimit,但无法重现

Apache 昨晚死了。错误日志显示

[alert] (11)Resource temporarily unavailable: setuid: unable to change to uid: 48

浏览互联网,似乎每个人都说这是 Linux 中 ulimit 的问题。如果我理解正确的话,ulimit 默认将任何非 root 用户的并发进程数限制为 1024。如果用户(在本例中为 apache)达到该最大数量,则无法创建更多进程。这解释了为什么它在尝试生成新子进程时无法将 uid 设置为 apache 用户。

昨晚,我们的 Web 应用的一个用户在大约 1 分钟的时间内对同一页面发出了 1100 多个 GET 请求,这时服务器崩溃了。

我的 Apache 配置文件有以下内容:

<IfModule prefork.c>
StartServers       8
MinSpareServers    5
MaxSpareServers   20
ServerLimit      2000
MaxClients       2000
MaxRequestsPerChild  4000
</IfModule>

KeepAlive On
MaxKeepAliveTimeout 5
KeepAliveTimeout 5

如果我的 MaxClients 是 2000,而 MaxSpareServers 是 20,那么就意味着 Apache 要达到进程数的 ulimit,就必须有 1000+ 个进程忙碌的进程,考虑到这些 GET 请求很小,每秒可以轻松处理 20-30 个请求,我根本看不到这种情况发生。最重要的是,MaxRequestsPerChild 设置为 4000,所以它不应该产生这么多新的子进程,对吧?ulimit 也是如此真的这里的罪魁祸首为什么不能setuid?

我曾使用 Apache 的ab工具尝试在性能较差的本地版本上重现此问题,但未能成功。即使是性能较差的硬件也可以在一分钟内处理数千个连接,好的性能。如果我尝试同时通过 Web 访问服务器,它会变得很慢,但 Apache 不会崩溃。

我的问题是:

  1. 有没有更好的方法来配置 prefork 模块?我们刚刚从旧服务器迁移到这个新服务器。旧服务器的 ServerLimit 和 MaxClients 设置为 512。我想最好将其设置为 2000,以避免在可预见的将来再次更改它。
  2. 我尝试将 ulimit nproc 调整为较低的数字,以尝试重现错误。我在 limits.conf 中设置了* hard nproc 15,但当我运行 时,Apache 仍会生成大约 30 个子进程ab。我是否遗漏了什么?
  3. 尽管有第 2 个问题,但这里的解决方案是将 nproc 设置提高到更高的值,例如 10000?
  4. 我还想实现一些可以阻止用户进行如此多次尝试的方法。过去,我曾经iptables阻止过一分钟内发出超过 5 次 SSH 请求的用户。我考虑过对 http 请求做类似的事情,但我想知道是否有更好的解决方案。我听说过 fail2ban 和 mod_security 等,但我不确定它们的作用是什么。在这种情况下,它们对我有用吗?还有其他建议吗?

服务器信息:RHEL 6.3,Apache 2.2.15

相关内容