我的服务器运行的是 Ubuntu 12.04 LTS(精确版),我遇到了一个奇怪的问题。该服务器托管一个用于数据收集的大型网站。该网站使用 PHP 语言编写并使用 Zend Framework。数据位于 MySQL 数据库中。该数据的一部分(来自调查)每小时(cron 作业)被渲染到 Excel 文件中(使用 PHPExcel 库)。此过程(PHP/Zend Framework 脚本)针对每个客户端执行,每个客户端都有不同的数据集,有时可能需要很长时间(30 多分钟)。
一旦达到 30 分钟,进程状态就会从 R 变为 D。奇怪的是,处于 D 状态的进程通常是“不可终止的”,但这个进程可以像任何其他进程一样被终止。以下是进程正常运行时的示例输出:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
www 16089 0.5 0.8 311640 31708 ? S 09:34 0:39 /usr/sbin/apache2 -k start
www 17635 0.6 0.6 305020 23396 ? S 10:52 0:18 /usr/sbin/apache2 -k start
www 18520 0.0 0.0 63104 1960 pts/0 S 11:32 0:00 su www
www 18521 0.0 0.1 23236 4516 pts/0 S 11:32 0:00 bash
www 18621 98.8 68.1 2665208 2416568 pts/0 R 11:33 10:48 php run.php -a hourly
www 18659 0.6 0.6 302848 22948 ? S 11:34 0:03 /usr/sbin/apache2 -k start
www 18876 0.0 0.0 18160 1244 pts/0 R+ 11:44 0:00 ps ux
您可以看到该过程占用大量资源:它已经被修剪了很多,并且仍在进行手术,但我需要它完成,以便我可以获得生成的 Excel 文件。该过程正在记录其大量活动(每个 Excel 文件约 300k 个日志),并且日志文件总是突然结束。我找不到任何地方记录错误。
以下是 30 分钟之后的相同进程列表:
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
www 18034 1.0 0.7 312412 26632 ? S 11:13 0:33 /usr/sbin/apache2 -k start
www 18245 2.1 0.4 303656 16912 ? S 11:25 0:49 /usr/sbin/apache2 -k start
www 18520 0.0 0.0 63104 296 pts/0 S 11:32 0:00 su www
www 18521 0.0 0.0 23236 968 pts/0 S 11:32 0:00 bash
www 18621 96.3 85.0 3969192 3012596 pts/0 D 11:33 30:08 php run.php -a hourly
www 18659 0.4 0.5 302856 19136 ? S 11:34 0:08 /usr/sbin/apache2 -k start
www 19431 0.0 0.0 18160 1240 pts/0 R+ 12:04 0:00 ps ux
如果继续运行,该进程仍会消耗资源,但不会执行任何操作。不会再记录任何内容。
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
www 18621 9.1 80.0 4030532 2835032 ? D 11:33 33:19 php run.php -a hourly
请注意,进程的状态会在 30 分钟后发生变化,根据服务器负载,它会处理更多或更少的数据。有趣的是,这只发生在生产服务器上。我的开发服务器 Ubuntu 12.04 也没有这个问题。
是否有什么东西会导致进程正常运行最多 30 分钟,然后将其状态更改为 D?什么可能导致 PHP 脚本最终处于 D 状态?
答案1
首先,处于 D 状态的进程不可中断睡眠(通常是 IO)。
通常导致进程进入此状态的原因是执行了阻塞系统调用。
您可以查看您的进程最后一次调用的内容strace
:
strace -fp <pid>
因为 D 状态通常是由 IO 操作引起的,所以使用以下命令检查进程打开了哪些文件也很有用lsof
:
lsof -p <pid>