RequestTimeout使用PHP上传到S3

时间:2011-05-20 13:33:23

标签: php amazon-s3

我无法从我们的某台服务器上传文件到S3。我们使用S3存储备份,所有服务器都运行Ubuntu 8.04,PHP 5.2.4和libcurl 7.18.0。每当我尝试上传文件时,亚马逊都会返回RequestTimeout错误。我知道我们当前版本的libcurl中存在一个错误,导致上传超过200MB。因此,我们将备份拆分为较小的文件。

我们在亚马逊的EC2上托管服务器,在客户的“私有云”(公司防火墙后面的VMWare ESX盒)上托管服务器。我遇到问题的特定服务器托管在客户的私有云上​​。

我们使用http://undesigned.org.za/2007/10/22/amazon-s3-php-class中的Amazon S3 PHP类。我尝试过200MB,100MB和50MB文件,结果相同。我们使用以下内容上传文件:

$s3 = new S3($access_key, $secret_key, false);
$success = $s3->putObjectFile($local_path, $bucket_name,
    $remote_name, S3::ACL_PRIVATE);

我尝试设置curl_setopt($curl, CURLOPT_NOPROGRESS, false);以在上传文件时查看进度条。我第一次使用此选项运行它设置它有效。但是,每次都失败了。它似乎以大约3Mb / s上传文件5-10秒然后下降到0.在20秒后坐在0,亚马逊返回“RequestTimeout - 你的套接字连接到服务器没有读取或写入超时期间。空闲连接将被关闭。“错误。

我尝试将S3类更新为GitHub的最新版本,但没有区别。我还找到了Amazon S3 Stream Wrapper类,并尝试使用以下代码:

include 'gs3.php';
define('S3_KEY', 'ACCESSKEYGOESHERE');
define('S3_PRIVATE','SECRETKEYGOESHERE');
$local = fopen('/path/to/backup_id.tar.gz.0000', 'r');
$remote = fopen('s3://bucket-name/customer/backup_id.tar.gz.0000', 'w+r');

$count = 0;
while (!feof($local))
{
    $result = fwrite($remote, fread($local, (1024 * 1024)));
    if ($result === false)
    {
        fwrite(STDOUT, $count++.': Unable to write!'."\n");
    }
    else
    {
        fwrite(STDOUT, $count++.': Wrote '.$result.' bytes'."\n");
    }
}

fclose($local);
fclose($remote);

此代码一次读取一个MB文件,以便将其流式传输到S3。对于一个50MB的文件,我得到“1:写入1048576字节”49次(第一个数字当然每次都改变)但是在循环的最后一次迭代中我得到一个错误,上面写着“通知:fputs():发送8192字节失败,errno = 11资源在第230行的/path/to/http.php中暂时不可用“。

我首先想到的是这是一个网络问题。我们打电话给客户并解释了问题,并要求他们查看他们的防火墙,看看他们是否放弃了任何东西。据他们的网络管理员说,流量很好。

我不知道接下来我能做些什么。我一直在手动运行备份,并使用SCP将它们转移到另一台机器并上传它们。这显然不太理想,我们将非常感谢任何帮助。

更新 - 2011年6月23日

我尝试了下面的许多选项,但它们都提供了相同的结果。我发现即使尝试将有问题的服务器中的文件scp到另一台服务器也会立即停止并最终超时。但是,我可以使用scp从另一台机器下载相同的文件。这让我更加确信这是客户端的网络问题,我们将非常感谢任何进一步的建议。

5 个答案:

答案 0 :(得分:4)

存在此问题是因为您尝试再次上载同一文件。例如:

$s3 = new S3('XXX','YYYY', false);
$s3->putObjectFile('file.jpg','bucket-name','file.jpg');
$s3->putObjectFile('file.jpg','bucket-name','newname-file.jpg');

要修复它,只需复制文件并为其指定新名称,然后正常上传。

示例:

$s3 = new S3('XXX','YYYY', false);
$s3->putObjectFile('file.jpg','bucket-name','file.jpg');
now rename file.jpg to newname-file.jpg
$s3->putObjectFile('newname-file.jpg','bucket-name','newname-file.jpg');

答案 1 :(得分:2)

我以另一种方式解决了这个问题。我的错误是,filesize()函数返回无效的缓存大小值。所以只需使用clearstatcache()

答案 2 :(得分:1)

我多次经历过同样的问题。

我现在有很多脚本,它们不断地将文件上传到S3。

我可以提供的最佳解决方案是使用Zend库(流包装器或直接S3 API)。

http://framework.zend.com/manual/en/zend.service.amazon.s3.html

自Zend框架的最新版本发布以来,我没有看到任何超时问题。但是,如果您发现自己仍然遇到问题,可以通过简单的调整来解决问题。

只需打开文件Zend / Http / Client.php并修改$ config数组中的'timeout'值即可。在撰写本文时,它存在于第114行。在最新版本之前,我的运行速度为120秒,但现在情况正常,10秒超时。

希望这有帮助!

答案 3 :(得分:1)

有很多可用的解决方案。我有这个确切的问题,但我不想编写代码并找出问题所在。

最初我正在寻找在Linux机器上安装S3存储桶的可能性,发现了一些有趣的东西:

  

s3fs - http://code.google.com/p/s3fs/wiki/InstallationNotes      - 这确实对我有用。它使用FUSE文件系统+ rsync来同步S3中的文件。它键入了本地系统中所有文件名的副本。使它看起来像一个文件/文件夹。

这节省了我们时间的BUNCH +编写用于传输文件的代码的麻烦。

现在,当我试图查看是否还有其他选项时,我发现了一个可在CLI中运行的ruby脚本,可以帮助您管理S3帐户。

  

s3cmd - http://s3tools.org/s3cmd - 这看起来很清楚。

[UPDATE] 找到了另一个CLI工具 - s3sync

  

s3sync - https://forums.aws.amazon.com/thread.jspa?threadID=11975&start=0&tstart=0 - 在亚马逊AWS社区中找到。

我没有看到它们两者不同,如果你不担心磁盘空间,那么我会选择s3fs而不是s3cmd。磁盘让您感觉更舒服+您可以看到磁盘中的文件。

希望它有所帮助。

答案 4 :(得分:1)

您应该查看AWS PHP SDK。这是以前称为tarzan和cloudfusion的AWS PHP库。

http://aws.amazon.com/sdkforphp/

此类附带的S3类坚如磐石。我们一直用它来上传多GB文件。