Сгенерировать большой zip-файл в asp net core

#asp.net-mvc #asp.net-core #zip #out-of-memory

#asp.net-mvc #asp.net-core #zip #нехватка памяти

Вопрос:

Я создаю действие контроллера MVC, которое создает zip-файл, содержащий два файла :

  • Некоторые метаданные сериализованы из базы данных.
  • Связанный файл содержимого фактически хранится в большом двоичном объекте хранилища Azure

Пока что мой контроллер работает нормально до определенного размера файла. Затем, когда содержимое из azure становится слишком большим, у меня возникает исключение нехватки памяти, определенно связанное с тем фактом, что я записываю данные в память сервера, которая не бесконечна.

Итак, теперь мне интересно, какой подход мне следует использовать? Записать данные по временному пути на сервере или есть другие варианты?

Вот мой контроллер aciton для справки :

 public async Task<ActionResult> Download(Guid? id)
    {

        if (id == null)
        {
            return NotFound();
        }

        var cIApplication = await _context.CIApplications
            .AsNoTracking()
            .SingleOrDefaultAsync(m => m.ID == id);
        if (cIApplication == null)
        {
            return NotFound();
        }

        //Serialize metadata : this will always be small
        byte[] metaData = BinSerializer.SerializeToByteArrayAsync<CIApplication>(cIApplication);

        //GetFile from Azure blob : This can reach several GB
        //StorageManagement is an helper class to manipulate Azure storage objects
        StorageManagement storage = new StorageManagement();
        byte[] content = await storage.GetBlobToStream("application", $"{cIApplication.ID}.zip");

        //Zip It and send it
        using (MemoryStream ms = new MemoryStream())
        {
            using (var archive = new ZipArchive(ms, ZipArchiveMode.Create, true))
            {
                var zipArchiveEntry = archive.CreateEntry($"{cIApplication.ID}.bin", CompressionLevel.Fastest);
                using (var zipStream = zipArchiveEntry.Open()) zipStream.Write(metaData, 0, metaData.Length);

                zipArchiveEntry = archive.CreateEntry($"{cIApplication.ID}.zip", CompressionLevel.Fastest);
                using (var zipStream = zipArchiveEntry.Open()) zipStream.Write(content, 0, content.Length);
            }
            return File(ms.ToArray(), "application/zip", $"{cIApplication.Publisher} {cIApplication.Name} {cIApplication.Version}.zip");
        }
    }
  

Комментарии:

1. Обычно, да, вы подключаетесь к файловой системе, чтобы свести использование памяти к минимуму. Тем не менее, я считаю, что создание zip-файла из этого в любом случае вызовет у вас проблемы, поскольку для этого его все равно придется загружать в память. Скорее всего, вам придется просто масштабировать ОЗУ на сервере по вертикали, чтобы компенсировать это. Вы также можете рассмотреть возможность переноса этого в фоновый процесс, который может выполняться на другом сервере с меньшим количеством приложений, претендующих на оперативную память. Затем вы даже можете настроить очередь, чтобы вам не приходилось выполнять несколько операций архивирования одновременно.

2. Я не знаком с Azure, но ваша проблема типична. Вы должны загружать content фрагментами и архивировать его по частям. Google показывает мне некоторые результаты за считанные минуты для azure blob stream chunk download и c# zip chunk .