如何使用本机sftp函数和PHP中的fwrite提高文件上传的性能

问题描述

嗨,我正在使用以下代码将大文件(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发布发送文件而没有任何问题。

有人可以在这里帮助吗?

非常感谢,也最好, intxcc

解决方法

问题在于,即使先读取32MB,然后再写入sftp流,fwrite也会以不同的大小分块。我认为只有几个KB。

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

所以解决方案是使用来增加sftp流的块大小

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);

希望这可以帮助下一个正在染白头发的人找出来;)