【问题标题】:How to increase the performance of a file upload using native sftp functions and fwrite in PHP如何使用原生 sftp 函数和 PHP 中的 fwrite 提高文件上传的性能
【发布时间】:2020-11-03 18:57:59
【问题描述】:

您好,我正在使用以下代码将一个大文件 (500MB) 上传到 sftp 服务器。

<?php

$connection = ssh2_connect($this->host, $this->port, null);
$sftp = ssh2_sftp($connection);

$connection_string = ((int) $sftp) . $remotePath . $remoteFilename;
$stream = fopen('ssh2.sftp://' . $connection_string, 'w');
$source = fopen($localFilepath, 'r');

if (!$stream) {
    throw new Exception('Could not create file: ' . $connection_string);
}

while (!feof($source)) {
    // Chunk size 32 MB
    if (fwrite($stream, fread($source, 33554432)) === false) {
        throw new Exception('Could not send data: ' . $connection_string);
    }
}

fclose($source);
fclose($stream);

但上传速度非常慢。代码在 Google Cloud Run 上运行。上传速度约为 8 MiB/s。

我也尝试通过 shell_exec 使用 lftp,但由于 Cloud Run,这会导致更多问题。

上行链路不是问题,因为我可以通过 CURL post 发送文件而没有任何问题。

有人可以帮忙吗?

非常感谢和最好的, intxcc

【问题讨论】:

  • 对于 ssh2_scp_send 我不确定,因为它是另一个协议,不是吗?使用 phpseclib,我遇到了一些晦涩难懂的公钥算法的问题。由于这是一项要求,用户可以设置密钥算法并想要所有这些算法,我认为本机 sftp 将是最安全的选择。
  • 当然,通常他们支持它——但在这种情况下,我需要一个稳定的解决方案。所以大部分支持它是行不通的。实际上,用户可以在 scp 和 sftp 之间进行选择,所以当他们选择 sftp 时,我很确定他们期望 sftp。在这项工作 1 年后解决没有 scp 的罕见的 sftp 边缘情况听起来并不有趣 ^^
  • 我不确定你是否知道我已经解决了这个问题并回答了这个问题(只是之前无法找到答案,这就是我在这里发布这个问题的原因)问题确实是块fwrite 的大小。默认情况下它只有几 KB,因为它通常用于文件系统。所以是的,仅凭问题中提供的信息,本机 sftp 可能非常糟糕。但似乎不是:) stream_set_chunk_size($stream, 1024 * 1024); 解决了这个问题
  • 感谢您的意见!编辑:是的,我需要等待 2 天才能批准我自己的答案

标签: php upload sftp fwrite ssh2-sftp


【解决方案1】:

问题在于,即使 32MB 被读取然后写入 sftp 流,fwrite 也会以不同的大小进行分块。我想只有几 KB。

对于文件系统(这是 fwrite 的常见情况),这很好,但由于 fwrite 到远程服务器而导致高延迟。

所以解决方法是增加sftp流的chunk大小

stream_set_chunk_size($stream, 1024 * 1024);

所以最终的工作代码是:

<?php

$connection = ssh2_connect($this->host, $this->port, null);
$sftp = ssh2_sftp($connection);

$connection_string = ((int) $sftp) . $remotePath . $remoteFilename;
$stream = fopen('ssh2.sftp://' . $connection_string, 'w');
$source = fopen($localFilepath, 'r');

// Stream chunk size 1 MB
stream_set_chunk_size($stream, 1024 * 1024);

if (!$stream) {
    throw new Exception('Could not create file: ' . $connection_string);
}

while (!feof($source)) {
    // Chunk size 32 MB
    if (fwrite($stream, fread($source, 33554432)) === false) {
        throw new Exception('Could not send data: ' . $connection_string);
    }
}

fclose($source);
fclose($stream);

希望这有助于下一个白发的人试图弄清楚这一点;)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-13
    • 1970-01-01
    相关资源
    最近更新 更多