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
локальные данные в память сразу. Есть два способа решить это.
- В соответствии с официальной ссылкой REST здесь, как показано ниже.
Максимальный размер блочного блоба, созданного с помощью Put Blob, составляет 256 МБ для версии 2016-05-31 и более поздних версий и 64 МБ для более старых версий. Если размер вашего большого двоичного объекта превышает 256 МБ для версии 2016-05-31 и более поздних версий или 64 МБ для более старых версий, его необходимо загрузить в виде набора блоков. Для получения дополнительной информации см. Операции Put Block и Put Block. Нет необходимости также вызывать Put Blob, если вы загружаете BLOB-объект в виде набора блоков.
Таким образом, для блоба, состоящего из блочных блобов, вы можете попытаться получить список блобов через list_blob_blocks
записать эти блочные объекты один за другим в локальный файл.
- Создать URL-адрес блоба с токеном SAS через
signed_uri
как этот тестовый код, а затем загрузить BLOB-объект с помощью потоковой передачи, чтобы записать локальный файл.
Проблема в том, что get_blob
должен загружать данные в память сразу, а не передавать их на диск. В Chef у нас есть remote_file
ресурс, чтобы помочь с этой потоковой загрузкой, но вам нужно будет получить простой URL-адрес для большого двоичного объекта, а не загружать его, используя их драгоценный камень.
Я просто искал возможность использовать azure/storage/blob
библиотека для проекта dev-ops, над которым я работал, и мне кажется, что реализация довольно проста и не использует полный доступный базовый API. Например, загрузка выполняется медленно при потоковой передаче из файла, потому что, скорее всего, она не загружает фрагменты параллельно и т. Д. Я не думаю, что эта библиотека готова к производству, а открытый API Ruby отсутствует. Это открытый исходный код, поэтому, если у кого-то есть время, он может помочь внести свой вклад.