Функция DownloadTo в Azure SDK для CPP очень медленная.

Вопрос или проблема

Я интегрировал Azure SDK для CPP в свое приложение, и по сравнению с старым Azure SDK наблюдается значительное замедление. После обновления для загрузки параллелизма Azure-sdk-for-cpp загрузка работает лучше, но загрузка все еще ОЧЕНЬ МЕДЛЕННАЯ.

Это можно воспроизвести на простом примере, просто попытавшись загрузить файл размером 1 Гб из хранилища Azure на локальную файловую систему.

  • Старый SDK ~1 минута
  • Новый SDK ~5 минут

Старый SDK использовал CPP REST, который использовал concurrency::streams::istream m_stream; В новом SDK этого нет, кроме TransferOptions.Concurrency, который почти ничего не делает. Есть ли какая-то идея, как ускорить DownloadTo? Или параллелизм должен быть реализован поверх библиотеки?

// Авторские права (c) Microsoft Corporation.
// Лицензировано по лицензии MIT.

#include <azure/storage/blobs.hpp>

#include <cstdio>
#include <iostream>
#include <stdexcept>

std::string GetConnectionString()
{
  const static std::string ConnectionString = "";

  if (!ConnectionString.empty())
  {
    return ConnectionString;
  }
  const static std::string envConnectionString = std::getenv("AZURE_STORAGE_CONNECTION_STRING");
  if (!envConnectionString.empty())
  {
    return envConnectionString;
  }
  throw std::runtime_error("Не удалось найти строку подключения.");
}

int main()
{
  using namespace Azure::Storage::Blobs;

  const std::string containerName = "sample-container";
  const std::string blobName = "sample-blob";
  const std::string blobContent = "Привет, Azure!";

  auto containerClient
      = BlobContainerClient::CreateFromConnectionString(GetConnectionString(), containerName);

  containerClient.CreateIfNotExists();

  BlockBlobClient blobClient = containerClient.GetBlockBlobClient(blobName);

  std::vector<uint8_t> buffer(blobContent.begin(), blobContent.end());
  blobClient.UploadFrom(buffer.data(), buffer.size());

  Azure::Storage::Metadata blobMetadata = {{"key1", "value1"}, {"key2", "value2"}};
  blobClient.SetMetadata(blobMetadata);

  auto properties = blobClient.GetProperties().Value;
  for (auto metadata : properties.Metadata)
  {
    std::cout << metadata.first << ":" << metadata.second << std::endl;
  }
  // Мы знаем, что размер блоба небольшой, поэтому здесь безопасно приводить тип.
  buffer.resize(static_cast<size_t>(properties.BlobSize));

  blobClient.DownloadTo(buffer.data(), buffer.size());

  std::cout << std::string(buffer.begin(), buffer.end()) << std::endl;

  return 0;
}

Ответ или решение

Замедление функции DownloadTo в Azure SDK для C++

При использовании Azure SDK для C++ в вашем приложении может возникнуть довольно ощутимое замедление по сравнению с предыдущей версией SDK. В вашем случае, вы отметили, что функции загрузки работают быстрее после обновления, однако время скачивания 1 Гб файла возросло практически в пять раз. Давайте подробно разберем возможные причины этого замедления и предложим пути оптимизации.

1. Сравнение старой и новой архитектуры SDK

Старая версия SDK использовала CPP REST и предоставляла concurrency::streams::istream, что позволяло реализовать асинхронные операции и увеличивало производительность через конкурентное использование потоков. Новая версия SDK достаточно значительно изменила свою архитектуру и вместо этого фокусируется на TransferOptions.Concurrency, что, к сожалению, не дает желаемого результата в вашем случае.

2. Причины замедления

  • Стратегия передачи: Отсутствие параллелизма в скачивании данных может быть одной из основных причин замедления. В новой версии SDK функционал параллельных загрузок может быть ограничен. Возможно, стоит рассмотреть реализацию параллелизма на уровне приложения.

  • Фрагментация данных: В новой архитектуре SDK может отсутствовать поддержка разбивки больших файлов на более мелкие части для параллельной загрузки. Это может привести к замедлению в сравнении с более оптимизированной старой версией.

  • Настройка сети: Убедитесь, что ваша сеть не является узким местом. Возможно, стоит протестировать скачивание из другой сети или с помощью других инструментов для сравнения.

3. Рекомендации по оптимизации

Чтобы ускорить процесс загрузки в Azure SDK для C++, вы можете рассмотреть следующие подходы:

  • Имплементация пользовательского параллелизма: Если функциональность "Concurrency" не дает нужного эффекта, возможно, вам стоит реализовать параллельные запросы для скачивания файла. Вы можете разбить файл на несколько частей и загружать их параллельно, а затем объединить их на локальной машине.

  • Использование потоков: Рассмотрите возможность использования стандартных библиотек C++ для управления многопоточностью, чтобы организовать параллельные загрузки и соответственно увеличить производительность.

  • Настройка TransferOptions: Попробуйте поэкспериментировать с параметрами, которые предоставляет TransferOptions, и установите более высокие уровни параллелизма, если это поддерживается.

  • Мониторинг и отладка: Используйте инструменты мониторинга для анализа времени выполнения загрузок, чтобы понять, на каком этапе возникают задержки. Это может помочь идентифицировать узкие места.

4. Пример кода с параллельной загрузкой

Вот базовая структура, как можно подойти к задаче реализации параллельного скачивания:

#include <future>
#include <vector>
#include <azure/storage/blobs.hpp>

void DownloadBlobPart(const Azure::Storage::Blobs::BlockBlobClient &blobClient, size_t offset, size_t size, std::vector<uint8_t> &buffer) {
    // Реализуйте логику скачивания части файла с использованием blobClient
}

void ParallelDownload(const Azure::Storage::Blobs::BlockBlobClient &blobClient, size_t blobSize, size_t partSize) {
    std::vector<std::future<void>> futures;
    size_t numParts = (blobSize + partSize - 1) / partSize;
    std::vector<uint8_t> buffer(blobSize);

    for (size_t i = 0; i < numParts; ++i) {
        size_t offset = i * partSize;
        size_t size = std::min(partSize, blobSize - offset);
        futures.emplace_back(std::async(std::launch::async, DownloadBlobPart, blobClient, offset, size, std::ref(buffer)));
    }

    for (auto &f : futures) {
        f.get();
    }
}

Заключение

Проблема медленного скачивания файла с использованием нового Azure SDK для C++ требует особого внимания, планирования и возможной доработки кода на уровне приложения. Используя предложенные методы, вы сможете улучшить производительность загрузки. Оставайтесь в курсе обновлений и возможностей от Microsoft, так как будущие обновления SDK могут включать улучшения, которые могут устранить текущие недостатки.

Если у вас есть дополнительные вопросы или проблемы, не стесняйтесь обращаться за помощью.

Оцените материал
Добавить комментарий

Капча загружается...