如何将doObjectExist()请求批量处理到Amazon S3?

时间:2013-09-05 14:02:39

标签: php amazon-web-services amazon-s3

我需要检查S3中是否存在一组密钥,用于大量项目中的每一个。 (每组键与大量项目之一有关。)

我正在使用PHP SDK(v2)

目前我正在为每个密钥调用$client->doesObjectExist(BUCKET, $key),这是一个瓶颈(每次呼叫到S3的往返时间)。

我更喜欢做$client->doesObjectExist(BUCKET, $batch) $batch = array($key1, $key2 ... $keyn)之类的内容,并且客户端要检查所有这些密钥,然后返回一组响应(或其他类似结构)。

我遇到few references到“批量api”,听起来很有希望,但没有什么具体的。我猜这可能只出现在v1 SDK中。

3 个答案:

答案 0 :(得分:6)

您可以利用基础Guzzle库功能,使用AWS SDK for PHP执行并行请求。由于doesObjectExist方法在该引擎盖下实际执行HeadObject操作。您可以通过执行以下操作来创建HeadObject命令组:

use Aws\S3\S3Client;
use Guzzle\Service\Exception\CommandTransferException;

function doObjectsExist(S3Client $s3, $bucket, array $objectKeys)
{
    $headObjectCommands = array();
    foreach ($objectKeys as $key) {
        $headObjectCommands[] = $s3->getCommand('HeadObject', array(
            'Bucket' => $bucket,
            'Key'    => $key
        ));
    }

    try {
        $s3->execute($headObjectCommands); // Executes in parallel
        return true;
    } catch (CommandTransferException $e) {
        return false;
    }
}

$s3 = S3Client::factory(array(
    'key'    => 'your_aws_access_key_id',
    'bucket' => 'your_aws_secret_key',
));
$bucket = 'your_bucket_name';
$objectKeys = array('object_key_1', 'object_key_2','object_key_3');

// Returns true only if ALL of the objects exist
echo doObjectsExist($s3, $bucket, $objectKeys) ? 'YES' : 'NO';

如果你想要响应中的数据,除了键是否存在,你可以改变try-catch块来做这样的事情。

try {
    $executedCommands = $s3->execute($headObjectCommands);
} catch (CommandTransferException $e) {
    $executedCommands = $e->getAllCommands();
}

// Do stuff with the command objects
foreach ($executedCommands as $command) {
    $exists = $command->getResponse()->isSuccessful() ? "YES" : "NO";
    echo "{$command['Bucket']}/{$command['Key']}: {$exists}\n";
}

AWS SDK for PHP User Guide中提到了并行发送命令,但我也会看一下Guzzle batching documentation

答案 1 :(得分:0)

进行批量检查以查看是否存在某些密钥的唯一方法是列出存储桶中的对象。

对于list call AWS,最多可返回1000个密钥/呼叫,因此它比为每个密钥执行doesObjectExist调用要快得多。但是如果你有大量的密钥并且你只想检查它们中的几个,那么列出存储桶中的所有对象将是不切实际的,所以在这种情况下,你唯一的选择仍然是单独检查每个对象。

问题不在于PHP v2 SDK缺少批量功能,而是S3 API没有实现这样的批量处理。

答案 2 :(得分:0)

我在Jeremy Lindblom的回答的基础上。

只想指出您可以在每个命令上设置的OnComplete回调。

$bucket = 'my-bucket';
$keys = array('page1.txt', 'page2.txt');

$commands = array();
foreach ($keys as $key) {
    $commands[] = $s3Client->getCommand('HeadObject', array('Bucket' => $bucket, 'Key' => $key))
        ->setOnComplete(
            function($command) use ($bucket, $key)
            {
                echo "\nBucket: $bucket\n";
                echo "\nKey: $key\n";

                // see http://goo.gl/pIWoYr for more detail on command objects
                var_dump($command->getResult());
            }
        );
}

try {
    $ex_commands = $s3Client->execute($commands);
}
catch (\Guzzle\Service\Exception\CommandTransferException $e) {
    $ex_commands = $e->getAllCommands();
}

// this is necesary; without this, the OnComplete handlers wouldn't get called (strange?!?)
foreach ($ex_commands as $command)
{
    $command->getResult();
}

如果有人能够解释为什么我需要调用$command->getResult()来调用OnComplete处理程序,那将是很棒的。