我在我的其中一台服务器上运行 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>
以下是我目前所知道的情况:
从 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 有权限写入目录,并从目录中读取。
在规格相同的另一台服务器上运行相同的脚本可以正常工作。两台服务器的规格如下:
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,并且通过浏览器运行的脚本就可以正常工作。