Perl 中的 Rsync system() 执行随机失败并出现协议错误

Rsync system() execution in Perl fails randomly with protocol error

我们通常在 (Mod)Perl(和 PHP)中调用 rsync,并没有 运行 遇到太多问题,但我们 运行 在 运行 执行命令时出现偶尔的协议错误,而在后续请求 运行 时执行正常。有趣的是,即使我在代码中重试,对于同一个http请求,它每次都会失败,但是如果你发出另一个http请求,它很可能会成功。

代码如下所示:

$cmd = sprintf('rsync -auvvv --rsync-path="rsync --log-file=/tmp/ui-rsync.log" %s %s', "$fromDir/$fromBase/", "$path/$toBase/");
$exitCode = system($cmd);

--rsync-path 参数后来被添加到那里用于调试。这是没有帮助的。无论哪种方式都失败了。

错误如下所示:

rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(600) [sender=3.0.6]

或者像这样:

unexpected tag 93 [receiver]
rsync error: error in rsync protocol data stream (code 12) at io.c(1134) [receiver=3.0.6]
rsync: connection unexpectedly closed (9 bytes received so far) [sender]
rsync error: error in rsync protocol data stream (code 12) at io.c(600) [sender=3.0.6]

我调试了实际生成的命令,我可以 运行 手动执行它们。

http 用户可以 运行 命令正常。

同样,编程重试 永远不会 有效,但手动重试(点击触发它的同一 http 端点)几乎总是有效。

感谢任何帮助,因为这让我们发疯了......很长一段时间,尝试了许多修复。

如果这是真实的 heisenbug,您可以重试 rsync 大概三次,中间休息一下:

for my $n (1..3){
   my $exitCode = system($cmd);
   my_log_sub("SUCCESS: rsync succeded on try $n") + last if $exitCode==0;
   my_log_sub("ERROR: rsync $n of 3 failed: $cmd $! $?");
   sleep(1) if $n<3;
}

你检查过你的本地和远程日志了吗?失败后立即尝试 sudo ls -rtl /var/log/sudo ls -rtl /var/log/httpd/ 并在重试时 tail -f /var/log/one_of_the_newest_logs

您检查过远程磁盘是否已满或目录是否存在?防火墙问题?远程和本地 rsync 或 ssh 版本(非常)不同? (虽然我想这应该会显示更清晰的错误信息)

解决方案是将 system() 更改为反引号。严重地。我不知道为什么会这样。

字面上的变化是这样的:

# BAD:
$exitCode = system($cmd);
# GOOD:
`$cmd`;

如果我不得不猜测,我会说 shell 的初始化方式存在一些细微差别,可能是某些环境变量或内存位置未正确清理。不过我真的不知道。