ruby - 在 Ruby 中下载 Azure Blob 时出现 NoMemoryError

标签 ruby azure chef-infra azure-storage azure-blob-storage

环境:

  • Windows 10 x64
  • Ruby 2.1.0 32 位
  • Chef 2015年12月12日
  • azure gem 0.7.9
  • Azure-Storage Gem 0.12.1.preview

我正在尝试从容器下载约 880MB 的 blob。当我这样做时,在 Ruby 进程大小达到约 500MB 后,它会抛出以下错误:

C:/opscode/chefdk/embedded/lib/ruby/2.1.0/net/protocol.rb:102:in `read': failed to allocate memory (NoMemoryError)

我已经在 Ruby 内部和外部以及 Azure gem 和 Azure-Storage gem 上尝试过此操作。所有四种组合的结果都是相同的(Chef 中的 Azure、Ruby 中的 Azure、Chef 中的 Azure-Storage、Ruby 中的 Azure-Storage)。

我发现的针对此类问题的大多数故障排除都建议对下载进行流式传输或分块下载,但似乎没有相应的方法或 get_blob 选项来执行此操作。

代码:

require 'azure/storage'

# vars
account_name = "myacct"
container_name = "myfiles"
access_key = "mykey"
installs_dir = "myinstalls"

# directory for files
create_dir = 'c:/' + installs_dir
Dir.mkdir(create_dir) unless File.exists?(create_dir)

# create azure client
Azure::Storage.setup(:storage_account_name => account_name, :storage_access_key => access_key)
azBlobs = Azure::Storage::Blob::BlobService.new

# get list of blobs in container
dlBlobs = azBlobs.list_blobs(container_name)

# download each blob to directory
dlBlobs.each do |dlBlob|
    puts "Downloading " + container_name + "/" + dlBlob.name
    portalBlob, blobContent = azBlobs.get_blob(container_name, dlBlob.name)
    File.open("c:/" + installs_dir + "/" + portalBlob.name, "wb") {|f|

        f.write(blobContent)
    }
end

我还尝试使用 IO.binwrite() 而不是 File.open() 并得到了相同的结果。

建议?

最佳答案

正如 @coderanger 所说,您的问题是由于使用 get_blob 将数据立即本地化到内存中引起的。有两种方法可以解决。

  1. 根据官方 REST 引用 here如下。

The maximum size for a block blob created via Put Blob is 256 MB for version 2016-05-31 and later, and 64 MB for older versions. If your blob is larger than 256 MB for version 2016-05-31 and later, or 64 MB for older versions, you must upload it as a set of blocks. For more information, see the Put Block and Put Block Listoperations. It's not necessary to also call Put Blob if you upload the blob as a set of blocks.

因此,对于由 block blob组成的blob,可以尝试通过list_blob_blocks获取 block blob列表,将这些 block blob一一写入本地文件。

  • 通过 signed_uri 生成带有 SAS token 的 Blob URL,例如 this test code ,然后通过流式下载 blob 写入本地文件。
  • 关于ruby - 在 Ruby 中下载 Azure Blob 时出现 NoMemoryError,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43724274/

    相关文章:

    ruby-on-rails - Ruby 将 do-block 分配给数组

    ruby - 是否可以使用 watir 在浏览器中导航回来?

    azure - Azure Stack 上的 Runbook 部署

    amazon-web-services - 如何增加 AWS Opsworks 的部署超时限制?

    ruby - 如何进行稳定排序?

    azure - 在应用服务中使用 Azure Active Directory 身份验证时允许匿名访问终结点

    Azure AD B2C - 使用图形 API 填充 "Authentication Email"

    chef-infra - 用 Knife 从 Chef 服务器下载角色和 Recipe

    chef-infra - 什么时候使用shellout?

    javascript - 将 Middleman 数据文件夹中的 JSON 文件解析为 Javascript 文件作为数组