什么原因导致作为 cron 作业运行的 PHP 脚本最终处于 D 状态?

什么原因导致作为 cron 作业运行的 PHP 脚本最终处于 D 状态?

我的服务器运行的是 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>

相关内容