我怎样才能防止我的服务器被这个 Ubuntu cron 作业删除 PHP 会话的僵尸程序破坏?

我怎样才能防止我的服务器被这个 Ubuntu cron 作业删除 PHP 会话的僵尸程序破坏?

我最近登录时发现有几千个进程被标记为“僵尸”。经过进一步调查,我发现以下内容ps fax

  701 ?        Ss     0:28 cron
 3363 ?        S      0:00  \_ CRON
 3364 ?        Ss     0:00      \_ /bin/sh -c   [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) ! -execdir fuser -s {} 2>/dev/null \; -delete
 3371 ?        S      0:00          \_ find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +24 ! -execdir fuser -s {} ; -delete
 3451 ?        S      0:02              \_ fuser -s ./sess_jns5af2mvm81e2fg1rbuctlt54
 3452 ?        Z      0:00                  \_ [fuser] <defunct>
 3453 ?        Z      0:00                  \_ [fuser] <defunct>
 3454 ?        Z      0:00                  \_ [fuser] <defunct>

... many, many lines omitted ...

13642 ?        Z      0:00                  \_ [fuser] <defunct>

据我所知,这是一个脚本,用于/etc/cron.d/php在每个小时的 10 分钟和 40 分钟后清理死亡的 PHP 会话。

编辑:这是脚本的文本。它在 Ubuntu 上默认与 PHP 一起安装。

# /etc/cron.d/php5: crontab fragment for php5
#  This purges session files older than X, where X is defined in seconds
#  as the largest value of session.gc_maxlifetime from all your php.ini
#  files, or 24 minutes if not defined.  See /usr/lib/php5/maxlifetime

# Look for and purge old sessions every 30 minutes
09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) ! -execdir fuser -s {} 2>/dev/null \; -delete

由于某种原因(目前我猜是一个行为不当的网络爬虫在每次请求时都会创建一个新会话,但我仍在查看日志),有时 中有数千个被遗弃的 php 会话/var/lib/php/,并且当此脚本运行时,它会很乐意为每个会话生成一个新的 fuser 进程。这很快就会达到进程限制,并使系统变得缓慢。

除了删除这个 cron 作业并手动清理之外我还能做什么?

答案1

最好将逻辑移到find一个脚本中,该脚本循环遍历命令行上的所有文件,以查看它们是否被访问,如果没有,则删除它们:

#!/bin/bash

for x; do
  if ! /bin/fuser -s "$x" 2>/dev/null; then
    rm "$x"
  fi
done

然后将 cron 任务改为

09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) -execdir thatscript.sh {} +

这将find收集所有符合最大期限的会话文件,然后thatscript.sh一次性运行所有文件(由于+而不是;)。然后脚本负责确保文件未被使用并将其删除。这样,应该只有一个直接子进程本身,并且 bash 在清理和子进程find时应该不会遇到任何问题。fuserrm

find的文档中,不清楚如果文件名列表超出了 shell/OS 限制,find 是否会自动将其分成多个执行(13000 个文件可能会这样……旧版本的 bash 的默认命令行参数限制在 5000 左右)在这种情况下,您可以更改-execdir thatscript.sh {} +为 来-print0 | xargs -0 thatscript.sh划分xargs文件。

或者,如果您没有安装驱动器noatime,请更改-cmin-amin并完全放弃测试:

    09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -amin +$(/usr/lib/php5/maxlifetime) -delete

这将删除最后的所有会话文件访问超过 [命令输出maxlifetime] 分钟前。只要你没有任何 php 进程打开会话然后闲置很长时间(Debian 上的默认 maxlifetime 似乎是 24 分钟,这将是非常由于页面加载时间过长,因此不执行任何操作,这不应该破坏当前正在使用的任何会话。

答案2

我也有这个问题Ubuntu 11.10我通过编辑解决了这个问题:

/etc/cron.d/php5 

并将代码替换为:

09,39 *     * * *     root   [ -x /usr/lib/php5/maxlifetime ] && [ -d /var/lib/php5 ] && find /var/lib/php5/ -depth -mindepth 1 -maxdepth 1 -type f -cmin +$(/usr/lib/php5/maxlifetime) -delete

这是Ubuntu 11.04php 的 cron 作业。

答案3

修复脚本,使其等待其子进程或忽略 SIG_CHILD。您能将脚本放在我们能看见的地方吗?

更新:看起来你正在触发一个错误find

答案4

这也将会非常有帮助:

https://bugs.launchpad.net/ubuntu/+source/php5/+bug/876387

阅读评论#4 和#8,后者甚至修复了定影器本身!

相关内容