【问题标题】:Why is this SFTP download so slow?为什么这个 SFTP 下载这么慢?
【发布时间】:2020-11-14 10:32:43
【问题描述】:

点击后我有一个下载按钮,下载一个文件大约需要 15 秒,因为它必须 SFTP 到服务器,找到正确的路径/文件,并返回响应。

<a class="btn btn-primary btn-sm text-primary btn-download-1" onclick="startDownload('1')"><i class="fa fa-download "></i></a>

这是startDownload函数:

function startDownload(interfaceId) {
    window.location = "/nodes/interface/capture/download?port=" + interfaceId;
}

/nodes/interface/capture/download中的后端代码:

public function download_files()
{

    $dir = '';
    $portNumber = Request::get('port');
    $zipMe = false;

    $remotePath = "/home/john/logs/".$dir."/";

    if (!isset($dir) || $dir == null) {
        return redirect()->back()->withInput()->withFlashDanger('SFTP Could not connect.');
    }

    $acsIp =  explode('://', env('ACS_URL'));
    $acsIp =  explode(':',$acsIp[1])[0];
    $sftp = new SFTP($acsIp.':22');

    if (!$sftp->login('john', '***')) {
        return redirect()->back()->withInput()->withFlashDanger('SFTP Could not connect.');
    }

    // Get into the Specified Directory
    $sftpConn = Storage::disk('sftp');

    $SFTPFiles = $sftpConn->allFiles('/'.$dir);

    if ( count($SFTPFiles) > 0 ) {
        foreach ($SFTPFiles as $file) {
            $fileName = $file;
            break;
        }

    } else {
        \Log::info('Files Not found in the Remote!');
        return redirect()->back()->withInput()->withFlashDanger('Files Not found in the Remote!');
    }

    // Create and give 777 permission to remote-files directory
    if (!is_dir(public_path('remote-files/'.$dir))) {
        mkdir(public_path('remote-files/'.$dir), 0777, true);
    }

    $filesToZip = [];

    foreach ( $SFTPFiles as $fileName ) {
        if ( $fileName == '..' || $fileName == '.' ) {
            continue;
        } else if ( $fileName == '' ) {
            \Log::info('File not found');
            continue;
        }

        $fileName     = explode("/", $fileName);
        $onlyFileName = (!empty($fileName) && isset($fileName[1])) ? $fileName[1] : "";
        $filepath = $remotePath.$onlyFileName;

        if (strpos($onlyFileName , $portNumber) !== false) {


            // Download the remote file at specified location in Local
            if (!$sftp->get($filepath, 'remote-files/'.$dir.'/'.$onlyFileName))
            {
                die("Error downloading file ".$filepath);
            }

            $file = public_path('remote-files/'.$dir.'/').$onlyFileName;

            $headers = array(
                'Content-Description: File Transfer',
                'Content-Type: application/octet-stream',
                'Content-Disposition: attachment; filename="'.basename($file).'"',
                'Cache-Control: must-revalidate',
                'Pragma: public',
                'Content-Length: ' . filesize($file)
            );

            return Response::download($file, $onlyFileName, $headers);
        }

        // IF File is exists in Directory
        if ( file_exists( public_path('remote-files/'.$dir.'/').$onlyFileName ) ) {
            $filesToZip[] = public_path('remote-files/'.$dir.'/').$onlyFileName;
            \Log::info('File Generated '.'remote-files/'.$dir.'/'.$onlyFileName);

            // Remove Files from public/remote-files
            $this->removeDirAndFiles('', public_path('remote-files/'.$dir));
            exit;

        } else {
            \Log::info('File not Generated '.'remote-files/'.$dir.'/'.$onlyFileName);
        }
    }
}

这段代码确实有效,但需要大约 15 秒,这对于用例来说太长了。

有没有办法加快速度?我的代码有问题还是可以预期?我应该考虑切换到 SCP 吗?我应该重新考虑身份验证吗?

【问题讨论】:

  • 您要下载的文件大小是多少?我不知道你是否面临同样的问题,但无论如何看看here
  • 它把时间花在哪里了?打开 SFTP 连接?实际传输文件?文件有多大?你得到的速率(每秒字节数)是多少?
  • 文件大小为 4kb。如何调试需要时间的地方?如何查看转账费率?
  • 为什么不使用 SFTP 记录每个操作的时间或只是差分时间,您将看到每个操作的影响。 $dir 也是空的,所以远程路径有两个斜杠。
  • @cyber8200 用于测量时间这样做,在脚本的开头 do $start = time();在执行期间你可以做 $mid = time(); $time_spent = $mid - $start;这将为您提供从 $start 到 $mid 传递的秒数,依此类推,您可以迭代以查看哪个间隔花费了很多时间

标签: javascript php laravel sftp


【解决方案1】:

我更改了您的函数以测量不同部分的时间,因此您可以通过查看此字符串“### [TIME] --”的日志来了解是哪个部分减慢了您的应用程序速度

public function download_files()
{
    $start = time();
    $dir = '';
    $portNumber = Request::get('port');
    $zipMe = false;

    \Log::info("### [TIME] -- t1 =  " . (time() - $start));

    $remotePath = "/home/john/logs/".$dir."/";

    if (!isset($dir) || $dir == null) {
        return redirect()->back()->withInput()->withFlashDanger('SFTP Could not connect.');
    }

    $acsIp =  explode('://', env('ACS_URL'));
    $acsIp =  explode(':',$acsIp[1])[0];

    $t1 = time();

    $sftp = new SFTP($acsIp.':22');

    $t2 = time();
    \Log::info("### [TIME] -- SFTP Instantiation took " . ($t2 - $t1) . " secs");

    if (!$sftp->login('john', '***')) {
        return redirect()->back()->withInput()->withFlashDanger('SFTP Could not connect.');
    }

    $t1 = time();
    // Get into the Specified Directory
    $sftpConn = Storage::disk('sftp');

    $SFTPFiles = $sftpConn->allFiles('/'.$dir);

    $t2 = time();
    \Log::info("### [TIME] -- SFTPFiles list took " . ($t2 - $t1) . " secs");


    // this loop is not clear to me, you basically take the first element and
    // exit the loop
    if ( count($SFTPFiles) > 0 ) {
        foreach ($SFTPFiles as $file) {
            $fileName = $file;
            break;
        }
    } else {
        \Log::info('Files Not found in the Remote!');
        return redirect()->back()->withInput()->withFlashDanger('Files Not found in the Remote!');
}

    $t1 = time();

    // Create and give 777 permission to remote-files directory
    if (!is_dir(public_path('remote-files/'.$dir))) {
        mkdir(public_path('remote-files/'.$dir), 0777, true);
    }

    $t2 = time();
    \Log::info("### [TIME] -- Directory creation took " . ($t2 - $t1) . " secs");

    $filesToZip = [];
    $t1 = time();
    foreach ( $SFTPFiles as $fileName ) 
    {
        $start_loop_time = time();
        \Log::info("### [TIME] -- Loop for $fileName took " . (time() - $t1) . " secs");

        if ( $fileName == '..' || $fileName == '.' ) {
            continue;
        } else if ( $fileName == '' ) {
            \Log::info('File not found');
            continue;
        }

        $fileName     = explode("/", $fileName);
        $onlyFileName = (!empty($fileName) && isset($fileName[1])) ? $fileName[1] : "";
        $filepath = $remotePath.$onlyFileName;

        if (strpos($onlyFileName , $portNumber) !== false) {

             $responseCreationStart = time();
            // Download the remote file at specified location in Local
            if (!$sftp->get($filepath, 'remote-files/'.$dir.'/'.$onlyFileName))
            {
                die("Error downloading file ".$filepath);
            }

            $file = public_path('remote-files/'.$dir.'/').$onlyFileName;

            $headers = array(
                'Content-Description: File Transfer',
                'Content-Type: application/octet-stream',
                'Content-Disposition: attachment; filename="'.basename($file).'"',
                'Cache-Control: must-revalidate',
                'Pragma: public',
                'Content-Length: ' . filesize($file)
            );
            $responseCreationEnd = time();
            \Log::info("### [TIME] -- Response creation took " . ($responseCreationEnd  - $responseCreationStart ) . " secs");
            return Response::download($file, $onlyFileName, $headers);

        }

        // IF File is exists in Directory
        if ( file_exists( public_path('remote-files/'.$dir.'/').$onlyFileName ) ) {
            $t3 = time();
            $filesToZip[] = public_path('remote-files/'.$dir.'/').$onlyFileName;
            \Log::info('File Generated '.'remote-files/'.$dir.'/'.$onlyFileName);

            // Remove Files from public/remote-files
            $this->removeDirAndFiles('', public_path('remote-files/'.$dir));
            $t4 = time();
            \Log::info("### [TIME] -- Deletion took " . ($t4 - $t3) . " secs");
            exit;

        } else {
            \Log::info('File not Generated '.'remote-files/'.$dir.'/'.$onlyFileName);
        }

        \Log::info("### [TIME] -- Loop end reached in  " . (time() - $start_loop_time ) . " secs");
    }
}

【讨论】:

    【解决方案2】:

    您是否在代码中的任何位置设置了$dir 变量?因为按照我的阅读方式,它的唯一内容是,并且永远是一个空字符串。

    这在其他浏览器中也需要很长时间吗?按下按钮后,浏览器检查器的“网络”选项卡中是否弹出任何值得注意的内容?

    此外,也许您可​​以尝试将函数放在按钮元素中而不是超链接中。
    也许这种延迟是浏览器内部的某种超时,因为它正在等待另一个页面加载?

    因此,我建议不要使用按钮的超链接,而是尝试一下:

    <button class="btn btn-primary btn-sm text-primary btn-download-1" onclick="startDownload('1')"><i class="fa fa-download "></i></button>
    

    我很想知道会发生什么。 让我们更新!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-11
      • 1970-01-01
      • 1970-01-01
      • 2012-08-18
      • 2020-03-19
      • 2014-03-12
      相关资源
      最近更新 更多