5

我在同一个 LAN 上有 2 台 Linux 服务器。
使用 PHP 我需要将 100000 个小 (10KB) 文件从服务器 A 复制到服务器 B。

现在我正在使用 ssh2_scp_send 并且它非常慢(20 分钟内有 10K 个文件)。

如何让它更快?

4

4 回答 4

4

通过 SSH 隧道使用 gzipped TAR 非常快。数量级比 pure 快scp,尤其是对于许多小文件。这是linux 命令行的示例:

user@local# cd /source/ ; 焦油 czf - * | ssh user@remote "cd /target/ ; tar xzf -"


更新:根据要求,您可以使用纯 PHP 解决方案 - 玩弄这个棘手的部分。

注意:您需要PHP 的 libssh 扩展才能使其工作。此外,STDIN 似乎仅在使用 SSH 的流包装器时可用。

这几乎没有开销,因为它直接在流上运行,并且您的 CPU 很可能总是比您用于传输的网络链接快。

-z要权衡网络与 CPU 速度,您可以从命令行中删除该选项。(较少的 CPU 使用率,但线路上的更多数据)

代码示例:

<?php
$local_cmd = "cd /tmp/source && tar -czf - *";
$remote_cmd = "tar -C /tmp/target -xzf -";

$ssh = new SSH_Connection('localhost');
$auth = $ssh->auth_password('gast', 'gast');
$bytes = $ssh->command_pipe($local_cmd, $remote_cmd);
echo "finished: $bytes bytes of data transfered\n";

class SSH_Connection {
    private $link;
    private $auth;

    function __construct ($host, $port=22) {
        $this->link = @ssh2_connect('localhost', 22);
    }  

    function auth_password ($username, $password) {
        if (!is_resource($this->link))
            return false;
        $this->auth = @ssh2_auth_password($this->link, $username, $password); 
        return $this->auth;
    }   

    function command_pipe ($localcmd, $remotecmd) {
        if (!is_resource($this->link) || !$this->auth)
            return false;
        // open remote command stream (STDIN)
        $remote_stream = fopen("ssh2.exec://{$this->link}/$remotecmd", 'rw');
        if (!is_resource($remote_stream))
            return false;
        // open local command stream (STDOUT)
        $local_stream = popen($localcmd, 'r');
        if (!is_resource($local_stream))
            return false;
        // connect both, pipe data from local to remote
        $bytes = 0;
        while (!feof($local_stream)) 
            $bytes += fwrite($remote_stream,fread($local_stream,8192));
        // close streams
        fclose($local_stream);
        fclose($remote_stream);
        return $bytes; 
    }   

    function is_connected () { return is_resource($this->link); }
    function is_authenticated () { return $this->auth; }
}
于 2012-05-09T10:39:25.673 回答
0

另一种选择是 Zip:

<?php
$zip = new ZipArchive();

if ($zip->open('TempFileToTransfer.zip', ZIPARCHIVE::CREATE)!==TRUE) {
    exit("cannot open <$filename>\n");
}

$zip->addFile('File 1');
$zip->addFile('File 2');
$zip->addFile('File 3');
$zip->close();
?>

传输该文件并在另一端解压缩,然后在另一端使用 zip_entry_open 和 zip_entry_read。

我还建议一次说 1000 个文件?

于 2012-05-09T10:32:19.497 回答
0

您可以通过 PHP 执行外部进程吗?如果可以,rsync 是更快的复制方式

于 2012-05-09T10:25:19.483 回答
0

发送大量小文件的开销很可能是这里的减速。

您可以将其存档在本地服务器 shell_exec()

发送到远程服务器,ssh2_scp_send()

然后在另一端展开它。ssh2_exec()

我的感觉是archving/expanding的开销会更少,但我还没有测试过。

于 2012-05-09T10:37:03.017 回答