我想使用PHP脚本(这是一个备份脚本)将大约10GB的存档转移到我的Amazon S3存储桶。
我实际使用以下代码:
$uploader = new \Aws\S3\MultipartCopy($s3Client, $tmpFilesBackupDirectory, [
'Bucket' => 'MyBucketName',
'Key' => 'backup'.date('Y-m-d').'.tar.gz',
'StorageClass' => $storageClass,
'Tagging' => 'expiration='.$tagging,
'ServerSideEncryption' => 'AES256',
]);
try
{
$result = $uploader->copy();
echo "Upload complete: {$result['ObjectURL']}\n";
}
catch (Aws\Exception\MultipartUploadException $e)
{
echo $e->getMessage() . "\n";
}
我的问题是,几分钟后(假设为10分钟),我收到来自apache服务器的错误消息:504网关超时。 我知道这个错误与我的Apache服务器的配置有关,但我不想增加服务器的超时。
我的想法是使用PHP SDK低级API执行以下步骤:
我认为这应该可行,但在使用此方法之前,我想知道是否有更简单的方法来实现我的目标,例如使用高级API ......
有什么建议吗?
注意:我不是在寻找一些现有的脚本:我的主要目标是学习如何解决这个问题:)
致以最诚挚的问候,
梅西
答案 0 :(得分:0)
为什么不使用AWS CLI复制文件?您可以在CLI中创建脚本,这样一切都是AWS原生的。 (Amazon上有tutorial。)您可以使用scp命令:
Sql.newInstance
从我的角度来看,在AWS中进行工作会更容易,AWS具有移动文件和数据的功能。如果您想使用shell脚本,那么有关自动化EC2备份的article有一个很好的备份,还有关于备份选项的更多详细信息。
答案 1 :(得分:0)
要回答我自己的问题(我希望有一天可能对某人有帮助!),他就是我一步一步解决问题的方法:
1 /当我加载页面时,检查存档是否已存在。如果没有,我创建我的.tar.gz文件,然后使用header()重新加载页面。 我注意到这一步很慢,因为要存档大量数据。这就是我重新加载页面以避免在接下来的步骤中超时的原因!
2 /如果备份文件存在,我使用AWS MultipartUpload发送10个100MB的块。每次成功发送一个块时,我都会更新一个会话变量($ _SESSION ['backup'] ['partNumber']),以了解下一个需要上传的块是什么。 一旦发送了10个块,我会再次重新加载页面以避免超时。
3 /我重复第二步,直到完成所有部分的上传,使用我的会话变量知道下一个需要发送的上传部分。4 /最后,我完成了分段上传,并删除了本地存储的档案。
您可以在重新加载页面之前发送超过10次100MB的内容。我选择此值以确保即使下载速度很慢也不会达到超时。但我想我每次都可以轻松发送大约5GB的容量。 注意:您无法将脚本重定向到自身太多时间。有一个限制(我认为Chrome和Firefox之前大约有20次出错,而IE更多)。在我的情况下(存档大约10GB),每次重新加载1GB就可以了(该页面将被重新加载大约10次)。但是存档大小增加了,我每次都要发送更多的块。
这是我的完整脚本。我当然可以改进,但它现在运作得很好,它可以帮助有类似问题的人!
public function backup()
{
ini_set('max_execution_time', '1800');
ini_set('memory_limit', '1024M');
require ROOT.'/Public/scripts/aws/aws-autoloader.php';
$s3Client = new \Aws\S3\S3Client([
'version' => 'latest',
'region' => 'eu-west-1',
'credentials' => [
'key' => '',
'secret' => '',
],
]);
$tmpDBBackupDirectory = ROOT.'Var/Backups/backup'.date('Y-m-d').'.sql.gz';
if(!file_exists($tmpDBBackupDirectory))
{
$this->cleanInterruptedMultipartUploads($s3Client);
$this->createSQLBackupFile();
$this->uploadSQLBackup($s3Client, $tmpDBBackupDirectory);
}
$tmpFilesBackupDirectory = ROOT.'Var/Backups/backup'.date('Y-m-d').'.tar.gz';
if(!isset($_SESSION['backup']['archiveReady']))
{
$this->createFTPBackupFile();
header('Location: '.CURRENT_URL);
}
$this->uploadFTPBackup($s3Client, $tmpFilesBackupDirectory);
unlink($tmpDBBackupDirectory);
unlink($tmpFilesBackupDirectory);
}
public function createSQLBackupFile()
{
// Backup DB
$tmpDBBackupDirectory = ROOT.'Var/Backups/backup'.date('Y-m-d').'.sql.gz';
if(!file_exists($tmpDBBackupDirectory))
{
$return_var = NULL;
$output = NULL;
$dbLogin = '';
$dbPassword = '';
$dbName = '';
$command = 'mysqldump -u '.$dbLogin.' -p'.$dbPassword.' '.$dbName.' --single-transaction --quick | gzip > '.$tmpDBBackupDirectory;
exec($command, $output, $return_var);
}
return $tmpDBBackupDirectory;
}
public function createFTPBackupFile()
{
// Compacting all files
$tmpFilesBackupDirectory = ROOT.'Var/Backups/backup'.date('Y-m-d').'.tar.gz';
$command = 'tar -cf '.$tmpFilesBackupDirectory.' '.ROOT;
exec($command);
$_SESSION['backup']['archiveReady'] = true;
return $tmpFilesBackupDirectory;
}
public function uploadSQLBackup($s3Client, $tmpDBBackupDirectory)
{
$result = $s3Client->putObject([
'Bucket' => '',
'Key' => 'backup'.date('Y-m-d').'.sql.gz',
'SourceFile' => $tmpDBBackupDirectory,
'StorageClass' => '',
'Tagging' => '',
'ServerSideEncryption' => 'AES256',
]);
}
public function uploadFTPBackup($s3Client, $tmpFilesBackupDirectory)
{
$storageClass = 'STANDARD_IA';
$bucket = '';
$key = 'backup'.date('Y-m-d').'.tar.gz';
$chunkSize = 100 * 1024 * 1024; // 100MB
$reloadFrequency = 10;
if(!isset($_SESSION['backup']['uploadId']))
{
$response = $s3Client->createMultipartUpload([
'Bucket' => $bucket,
'Key' => $key,
'StorageClass' => $storageClass,
'Tagging' => '',
'ServerSideEncryption' => 'AES256',
]);
$_SESSION['backup']['uploadId'] = $response['UploadId'];
$_SESSION['backup']['partNumber'] = 1;
}
$file = fopen($tmpFilesBackupDirectory, 'r');
$parts = array();
//Reading parts already uploaded
for($i = 1; $i < $_SESSION['backup']['partNumber']; $i++)
{
if(!feof($file))
{
fread($file, $chunkSize);
}
}
// Uploading next parts
while(!feof($file))
{
do
{
try
{
$result = $s3Client->uploadPart(array(
'Bucket' => $bucket,
'Key' => $key,
'UploadId' => $_SESSION['backup']['uploadId'],
'PartNumber' => $_SESSION['backup']['partNumber'],
'Body' => fread($file, $chunkSize),
));
}
}
while (!isset($result));
$_SESSION['backup']['parts'][] = array(
'PartNumber' => $_SESSION['backup']['partNumber'],
'ETag' => $result['ETag'],
);
$_SESSION['backup']['partNumber']++;
if($_SESSION['backup']['partNumber'] % $reloadFrequency == 1)
{
header('Location: '.CURRENT_URL);
die;
}
}
fclose($file);
$result = $s3Client->completeMultipartUpload(array(
'Bucket' => $bucket,
'Key' => $key,
'UploadId' => $_SESSION['backup']['uploadId'],
'MultipartUpload' => Array(
'Parts' => $_SESSION['backup']['parts'],
),
));
$url = $result['Location'];
}
public function cleanInterruptedMultipartUploads($s3Client)
{
$tResults = $s3Client->listMultipartUploads(array('Bucket' => ''));
$tResults = $tResults->toArray();
if(isset($tResults['Uploads']))
{
foreach($tResults['Uploads'] AS $result)
{
$s3Client->abortMultipartUpload(array(
'Bucket' => '',
'Key' => $result['Key'],
'UploadId' => $result['UploadId']));
}
}
if(isset($_SESSION['backup']))
{
unset($_SESSION['backup']);
}
}
如果有人有疑问请不要犹豫与我联系:)