Azure SDK for php blob 下载导致内存不足

Posted

技术标签:

【中文标题】Azure SDK for php blob 下载导致内存不足【英文标题】:Azure SDK for php blob download causes out of memory 【发布时间】:2015-10-08 00:00:13 【问题描述】:

我正在使用 Azure blob 存储在云中存储大量 pdf 和 zip 文件。 我通过 azure sdk for php 访问文件并将文件直接推送给用户(当然用户不应该看到文件来自哪里,所以我不会将他重定向到 Microsoft url)。 我的代码如下所示:

$blobRestProxy = ServicesBuilder::getInstance()->createBlobService($this->azureConfig['connectionString']);

$blob = $blobRestProxy->getBlob($container, $blobName);
$properties = $blobRestProxy->getBlobProperties($container, $blobName);

$size = $properties->getProperties()->getContentLength();
$mime = $properties->getProperties()->getContentType();
$stream = $blob->getContentStream();

header("Pragma:no-cache");
header("Cache-Control: no-cache, must-revalidate");
header("Content-type: $mime");
header("Content-length: $size");

fpassthru($stream);

对于小文件,完全没有问题,对于较大的文件,我得到这个错误:

Fatal error: Out of memory (allocated 93323264) (tried to allocate 254826985 bytes) in \vendors\azure-sdk-for-php\WindowsAzure\Common\Internal\Utilities.php on line 450

有没有更好的方法在用户不认识的情况下通过 php 向用户提供云存储文件?

我已经找到了这个讨论 https://github.com/Azure/azure-sdk-for-php/issues/729,但是 curl 解决方案不起作用。

谢谢!

最好的 格什

【问题讨论】:

【参考方案1】:

据我了解,由于下载的文件更大,程序会消耗更多的内存。在这种情况下,我们可以采取这些措施来克服内存耗尽错误:

    设置 memory_limit 值。

有一个名为memory_limit 的PHP 环境配置来限制可以分配的内存。我们可以使用代码在php页面中设置memory_limit值:

ini_set("memory_limit","200M");

如果您不想设置文件大小,可以将 memory_limit 值设置为“-1”,就像:

ini_set("memory_limit","-1");

另一种方法,我们可以在配置文件(如 php.ini)中将其放大。这个official guide告诉你如何配置PHP环境。

    在卡盘中下载文件

我们还可以在卡盘中下载大型 blob 以减少内存开销。

查看BlobRestProxy.php中的SDK源码,有一个用于获取Blob的函数public function getBlob($container, $blob, $options = null),我们可以在$options中设置额外的参数,每次都分片获取Blob。这是我的代码 sn-p:

$properties = $blobRestProxy->getBlobProperties($container, $blobName);
$size = $properties->getProperties()->getContentLength();
$mime = $properties->getProperties()->getContentType();
$chunk_size = 1024 * 1024;
$index = 0;
//$stream = "";

header("Pragma: public");
header('Content-Disposition: attachment; filename="' . $blobName . '"');
header('Expires: 0');
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Transfer-Encoding: binary");
header("Content-type: $mime");
header("Content-length: $size");
ob_clean();

while ($index < $size) 
       $option = new GetBlobOptions();
       $option->setRangeStart($index);
       $option->setRangeEnd($index + $chunk_size - 1);
       $blob = $blobRestProxy->getBlob($container, $blobName, $option);
       $stream_t = $blob->getContentStream();
       $length = $blob->getProperties()->getContentLength();
       $index += $length;
       flush();
       fpassthru($stream_t);

如有任何疑问,请随时告诉我。

【讨论】:

您好,谢谢您的回答。第一个选项是不可能的,我不能增加内存限制。我尝试了第二种解决方案,但我得到了同样的错误,不管 chu​​nk_size 有多大。我不知道为什么,也许 BlobOptions 不能正常工作。 嗨@Gesh,BlobOptions 确实有自己的类类型Models\GetBlobOptions,并且还探索了一些设置\获取属性的功能。我们可以看到[源代码](github.com/Azure/azure-sdk-for-php/blob/master/WindowsAzure/…)。当然,要创建GetBlobOptions,我们需要首先引用命名空间use WindowsAzure\Blob\Models\GetBlobOptions;。顺便说一句,如果有任何错误消息显示给我,那就更好了。 嗨@Gary,我当然添加了使用WindowsAzure\Blob\Models\GetBlobOptions;。所以我得到的错误是:Error: Allowed memory size of 268435456 bytes exhausted (tried to allocate 254826985 bytes) File: /vendors/azure-sdk-for-php/WindowsAzure/Common/Internal/Utilities.php Line: 450 所以我之前得到了同样的错误。 它似乎没有被分割成块。我们可以在getBlob之前var_export($option)检查范围是否在循环中。 选项如下所示:object(WindowsAzure\Blob\Models\GetBlobOptions) [private] _leaseId =&gt; null [private] _snapshot =&gt; null [private] _accessCondition =&gt; null [private] _computeRangeMD5 =&gt; null [private] _rangeStart =&gt; (int) 0 [private] _rangeEnd =&gt; (int) 1048575 object(WindowsAzure\Blob\Models\GetBlobOptions) [private] _leaseId =&gt; null [private] _snapshot =&gt; null [private] _accessCondition =&gt; null [private] _computeRangeMD5 =&gt; null [private] _rangeStart =&gt; (int) 1048576 [private] _rangeEnd =&gt; (int) 2097151

以上是关于Azure SDK for php blob 下载导致内存不足的主要内容,如果未能解决你的问题,请参考以下文章

Azure Blob PHP SDK - 直接从自定义多部分 API 请求上传到 Azure 存储

Azure Blob Storage SDK for .NET BlobClient.UploadAsync 总是抛出异常,但总是上传文件

Azure Storage Blob Go SDK示例

如何在 Azure blob 下载中获取 blob 下载进度

使用 Blob 服务客户端查找 azure 帐户密钥失败(azure python sdk)

未从 blob 上的 azure java sdk 收到元数据字段