NoMemoryError при загрузке BLOB-объекта Azure в Ruby

Среда:

  • Windows 10 x64
  • Ruby 2.1.0 32 бит
  • Шеф-повар 12.12.15
  • Лазурный камень 0.7.9
  • Azure-Storage Gem 0.12.1.preview

Я пытаюсь загрузить блоб размером ~880 МБ из контейнера. Когда я делаю это, он выдает следующую ошибку после того, как размер процесса Ruby достигает ~500 МБ:

C: /opscode/chefdk/embedded/lib/ruby/2.1.0/net/protocol.rb: 102: в `read': не удалось выделить память (NoMemoryError)

Я пробовал это как внутри, так и снаружи Ruby, а также с гемом Azure и гем Azure-Storage. Результат одинаков для всех четырех комбинаций (Azure в Chef, Azure в Ruby, Azure-Storage в Chef, Azure-Storage в Ruby).

Большая часть устранения неполадок, которые я обнаружил для подобных проблем, предполагает потоковую передачу или загрузку по частям, но, похоже, нет соответствующего метода или опции 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() и получил тот же результат.

Предложения?

2 ответа

Решение

Как сказал @coderanger, ваша проблема была вызвана использованием get_blob локальные данные в память сразу. Есть два способа решить это.

  1. В соответствии с официальной ссылкой REST здесь, как показано ниже.

Максимальный размер блочного блоба, созданного с помощью Put Blob, составляет 256 МБ для версии 2016-05-31 и более поздних версий и 64 МБ для более старых версий. Если размер вашего большого двоичного объекта превышает 256 МБ для версии 2016-05-31 и более поздних версий или 64 МБ для более старых версий, его необходимо загрузить в виде набора блоков. Для получения дополнительной информации см. Операции Put Block и Put Block. Нет необходимости также вызывать Put Blob, если вы загружаете BLOB-объект в виде набора блоков.

Таким образом, для блоба, состоящего из блочных блобов, вы можете попытаться получить список блобов через list_blob_blocks записать эти блочные объекты один за другим в локальный файл.

  1. Создать URL-адрес блоба с токеном SAS через signed_uri как этот тестовый код, а затем загрузить BLOB-объект с помощью потоковой передачи, чтобы записать локальный файл.

Проблема в том, что get_blob должен загружать данные в память сразу, а не передавать их на диск. В Chef у нас есть remote_file ресурс, чтобы помочь с этой потоковой загрузкой, но вам нужно будет получить простой URL-адрес для большого двоичного объекта, а не загружать его, используя их драгоценный камень.

Я просто искал возможность использовать azure/storage/blobбиблиотека для проекта dev-ops, над которым я работал, и мне кажется, что реализация довольно проста и не использует полный доступный базовый API. Например, загрузка выполняется медленно при потоковой передаче из файла, потому что, скорее всего, она не загружает фрагменты параллельно и т. Д. Я не думаю, что эта библиотека готова к производству, а открытый API Ruby отсутствует. Это открытый исходный код, поэтому, если у кого-то есть время, он может помочь внести свой вклад.

Другие вопросы по тегам