apache/mod_php 通过 exec() 运行 rsync 时出现的问题

apache/mod_php 通过 exec() 运行 rsync 时出现的问题

我在我的其中一台服务器上运行 rsync 的 php 脚本时遇到问题,但仅当通过 apache/mod_php 运行时才会出现。

以下是该脚本的精简版本:

<?php
 exec("rsync -a /var/www/html/from/ /var/www/html/to");
?>

很简单。此命令的目的是将文件夹结构(具有适当的权限)复制到新文件夹。但问题是,此 rsync 命令挂起并且无法完成。

经过一些调查,我注意到该脚本会产生两个 rsync 进程:

> ps aux | grep rsync
apache   20752 56.9  0.0  10400   656 ?     R   11:29  1:37 rsync -a /var/www/html/from/ /var/www/html/to
apache   20753  0.0  0.0  10400   276 ?     S   11:29  0:00 rsync -a /var/www/html/from/ /var/www/html/to
root     22305  0.0  0.0  61212   764 pts/1 S+  11:32  0:00 grep rsync

我注意到第一个进程处于“正在运行”状态。因此,我对其进行了 strace 操作,但得到的输出仅为以下内容:

> strace -p 20752
<snip>
select(1037, [1026 1027 1028 1029], [], NULL, {60, 0}) = 4 (in [1026 1027 1028 1029], left {60, 0})
select(1037, [1026 1027 1028 1029], [], NULL, {60, 0}) = 4 (in [1026 1027 1028 1029], left {60, 0})
select(1037, [1026 1027 1028 1029], [], NULL, {60, 0}) = 4 (in [1026 1027 1028 1029], left {60, 0})
select(1037, [1026 1027 1028 1029], [], NULL, {60, 0}) = 4 (in [1026 1027 1028 1029], left {60, 0})
select(1037, [1026 1027 1028 1029], [], NULL, {60, 0}) = 4 (in [1026 1027 1028 1029], left {60, 0})
select(1037, [1026 1027 1028 1029], [], NULL, {60, 0}) = 4 (in [1026 1027 1028 1029], left {60, 0})
select(1037, [1026 1027 1028 1029], [], NULL, {60, 0}) = 4 (in [1026 1027 1028 1029], left {60, 0})
select(1037, [1026 1027 1028 1029], [], NULL, {60, 0}) = 4 (in [1026 1027 1028 1029], left {60, 0})
select(1037, [1026 1027 1028 1029], [], NULL, {60, 0}) = 4 (in [1026 1027 1028 1029], left {60, 0})
select(1037, [1026 1027 1028 1029], [], NULL, {60, 0}) = 4 (in [1026 1027 1028 1029], left {60, 0})
<snip>

以下是我目前所知道的情况:

  1. 从 CLI 运行时,php 脚本运行良好。我启用了该功能su apache并运行脚本> php myscript.php,它运行良好。但运行http://mydomain.com/myscript.php创建了 2 个进程,其中第一个进程处于持续运行状态。这让我相信这不是权限问题。作为进一步的证明,下面是输出ls -l

    > ls -l /var/www | grep html
    drwxr-xr-x 79 apache    apacheftp 4096 Aug 17 12:07 html
    
    > ls -l /var/www/html | grep from
    drwxrwxr-x 2 apache apache 4096 Aug 22 11:27 from
    

    因此,apache 有权限写入目录,并从目录中读取。

  2. 在规格相同的另一台服务器上运行相同的脚本可以正常工作。两台服务器的规格如下:

    Apache version: Apache/2.2.3
    PHP version: 5.3.3
    rsync version: 2.6.8  protocol version 29
    OS: Red Hat Enterprise Linux Server release 5.6 (Tikanga)
    

我不知道为什么 apache 会生成两个 rsync 进程(或者为什么第一个 rsync 会生成第二个),以及为什么第一个 rsync 进程似乎卡在了select(1037...)

有人可以解释一下吗?

答案1

因此,修改我的脚本以直接通过函数运行 strace 后,exec()如下所示:

/usr/bin/strace -fo /var/www/html/rsynce.log /usr/bin/rsync -a /var/www/html/from/ /var/www/html/to

并检查通过浏览器运行生成的文件中的差异,并从命令行中发现了这一行(在从浏览器运行脚本生成的日志中):

select(1034, [1026 1027 1028 1029], [], NULL, {60, 0}) = -1 EBADF (Bad file descriptor)

这让我开始研究 Apache 中的文件描述符。在我的设置中,我运行了许多虚拟主机,每个虚拟主机都定义了 3 个唯一的日志文件。因此,虽然 Apache 进程使用了​​ 1143 个文件描述符(通过lsof -p pid | wc -l),但其中只有 124 个不是日志。

我能够从虚拟主机中删除唯一的日志文件,重新启动 apache,并且通过浏览器运行的脚本就可以正常工作。

相关内容