如果我理解你所说的一切,那么下载这么多对象的速度就没有办法解决了。 100,000,000 * 2.5MB = 250TB。这是很多数据。不过,您可以采取一些措施来提高效率。
如果您尝试通过使用S3\Client::getObjects 同步下载来“一次”获取多个(即数千个)对象,则需要很长时间。使用返回Guzzle\Promise\Promise 的S3\Client::getObjectsAsync 会更快一些。这并不是真正的异步。对 S3 的所有请求不会同时执行。无论如何,调用getObjectsAsync 将阻塞线程,直到请求完成。并且简单地遍历一个循环并调用Guzzle\Promise\Promise::wait 仍然需要很长时间。
但是,如果您分解请求并同时分批执行它们,您可以从请求中节省大量时间。 Guzzle 提供了一个 few options 来等待一系列承诺,但我更喜欢 Guzzle\Promise\unwrap 函数。它返回给它的 promise 数组的结果数组。
下面是我编写的一个生成器:
public function getObjectsBatch($bucket, $keys, $chunkSize = 350)
{
foreach (array_chunk($keys, $chunkSize) as $chunk) {
$promises = [];
foreach ($chunk as $key) {
$promises[] = $this->getClient()->getObjectAsync([
'Bucket' => $bucket,
'Key' => $key
])->then($success = function (Result $res) use ($key) {
$res->offsetSet('Key', $key);
return $res;
}, $fail = function (S3Exception $res) {
return $res;
});
}
yield unwrap($promises);
}
}
我正在使用它来下载数千个对象,并在下载时将它们流式传输给用户。
批次的大小很重要。在示例中,我一次执行 350 个请求。我做了一些测试,这似乎是最有效的。在我的测试中,我使用不同的批量从 S3 下载了 4500 个对象。我对每个批次大小进行了 10 次测试。 350 似乎是最有效的。
但您的特定用例(一次下载 250TB 的数据)无论采用何种方式都将需要很长时间。如果您不将文件保存到磁盘,您将很快耗尽内存,那么您还必须担心磁盘空间。我不确定您为什么需要下载这么多文件,但这似乎不是一个好主意。