Add Storage Performance tests for DownloadTo API (#2987)

Adding 3 new tests for Storage Performance
The next tests are expected to find out the overhead between each layer of the Azure SDK client while performing a download operation. The current performance test is measuring the client + azure core pipeline + http transport.

The next tests removes authentication policy and then each layer up to the HTTP transport adapter directly.

DownloadBlobSas
Generates a SaS token to download a blob. This way the authentication policy "sharedKey" won't run in the pipeline.

DownloadBlobWithPipelineOnly
Use the SaS token as well but send the request without the BlobClient. Instead it uses the Azure Core Pipeline directly

DownloadBlobWithTransportOnly
Same as before, the SaS token is used to download the blob but consuming only the libcurl-transport adapter. This option skips the HttpPipeline. The only elements used from Azure Core are the HttpRequest and the Azure::Context

Note
porting tests from the .NET equivalent:

https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Scenarios/DownloadSasUriBlobClient.cs

https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Scenarios/DownloadSasUriHttpClient.cs

https://github.com/Azure/azure-sdk-for-net/blob/main/sdk/storage/Azure.Storage.Blobs/perf/Azure.Storage.Blobs.Perf/Scenarios/DownloadSasUriHttpPipeline.cs
This commit is contained in:
Victor Vazquez 2021-10-25 11:48:55 -07:00 committed by GitHub
parent 3fdf66bb55
commit f90ab8a9b5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 385 additions and 6 deletions

View File

@ -6,6 +6,11 @@ project(azure-perf LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/../../../cmake-modules")
include(AzureTransportAdapters)
set(
AZURE_PERFORMANCE_HEADER

View File

@ -7,10 +7,17 @@ project(azure-storage-blobs-perf LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED True)
if(BUILD_TRANSPORT_CURL)
set(DOWNLOAD_WITH_LIBCURL inc/azure/storage/blobs/test/download_blob_transport_only.hpp)
endif()
set(
AZURE_STORAGE_BLOBS_PERF_TEST_HEADER
inc/azure/storage/blobs/test/blob_base_test.hpp
inc/azure/storage/blobs/test/download_blob_from_sas.hpp
inc/azure/storage/blobs/test/download_blob_pipeline_only.hpp
inc/azure/storage/blobs/test/download_blob_test.hpp
${DOWNLOAD_WITH_LIBCURL}
inc/azure/storage/blobs/test/list_blob_test.hpp
inc/azure/storage/blobs/test/upload_blob_test.hpp
)

View File

@ -25,13 +25,35 @@ namespace Azure { namespace Storage { namespace Blobs { namespace Test {
*
*/
class BlobsTest : public Azure::Perf::PerfTest {
private:
std::shared_ptr<Azure::Storage::StorageSharedKeyCredential> m_keyCredential;
protected:
std::string m_containerName;
std::string m_blobName;
std::string m_connectionString;
std::unique_ptr<Azure::Storage::Blobs::BlobServiceClient> m_serviceClient;
std::unique_ptr<Azure::Storage::Blobs::BlobContainerClient> m_containerClient;
std::unique_ptr<Azure::Storage::Blobs::BlockBlobClient> m_blobClient;
std::string GetSasToken()
{
// Generate SaS Token
auto sasStartsOn = std::chrono::system_clock::now() - std::chrono::minutes(5);
auto sasExpiresOn = std::chrono::system_clock::now() + std::chrono::minutes(60);
Sas::BlobSasBuilder blobSasBuilder;
blobSasBuilder.Protocol = Sas::SasProtocol::HttpsAndHttp;
blobSasBuilder.StartsOn = sasStartsOn;
blobSasBuilder.ExpiresOn = sasExpiresOn;
blobSasBuilder.BlobContainerName = m_containerName;
blobSasBuilder.BlobName = m_blobName;
blobSasBuilder.Resource = Sas::BlobSasResource::Blob;
blobSasBuilder.SetPermissions(Sas::BlobSasPermissions::All);
return blobSasBuilder.GenerateSasToken(*m_keyCredential);
}
public:
/**
* @brief Creat the container client
@ -48,12 +70,15 @@ namespace Azure { namespace Storage { namespace Blobs { namespace Test {
m_blobName = "blob" + Azure::Core::Uuid::CreateUuid().ToString();
// Create client, container and blobClient
m_serviceClient = std::make_unique<Azure::Storage::Blobs::BlobServiceClient>(
Azure::Storage::Blobs::BlobServiceClient::CreateFromConnectionString(m_connectionString));
m_containerClient = std::make_unique<Azure::Storage::Blobs::BlobContainerClient>(
Azure::Storage::Blobs::BlobContainerClient::CreateFromConnectionString(
m_connectionString, m_containerName));
m_serviceClient->GetBlobContainerClient(m_containerName));
m_containerClient->CreateIfNotExists();
m_blobClient = std::make_unique<Azure::Storage::Blobs::BlockBlobClient>(
m_containerClient->GetBlockBlobClient(m_blobName));
m_keyCredential = _internal::ParseConnectionString(m_connectionString).KeyCredential;
}
void Cleanup() override { m_containerClient->DeleteIfExists(); }

View File

@ -0,0 +1,95 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief Test the performance of downloading a block blob using SaS token.
*
*/
#pragma once
#include <azure/core/io/body_stream.hpp>
#include <azure/perf.hpp>
#include "azure/storage/blobs/test/blob_base_test.hpp"
#include <iostream>
#include <memory>
#include <string>
#include <vector>
namespace Azure { namespace Storage { namespace Blobs { namespace Test {
/**
* @brief A test to measure downloading a blob using SaS token.
*
*/
class DownloadBlobSas : public Azure::Storage::Blobs::Test::BlobsTest {
private:
std::unique_ptr<std::vector<uint8_t>> m_downloadBuffer;
std::unique_ptr<Azure::Storage::Blobs::BlockBlobClient> m_blobClientSas;
public:
/**
* @brief Construct a new DownloadBlobSas test.
*
* @param options The test options.
*/
DownloadBlobSas(Azure::Perf::TestOptions options) : BlobsTest(options) {}
/**
* @brief The size to upload on setup is defined by a mandatory parameter.
*
*/
void Setup() override
{
// Call base to create blob client
BlobsTest::Setup();
long size = m_options.GetMandatoryOption<long>("Size");
m_downloadBuffer = std::make_unique<std::vector<uint8_t>>(size);
auto rawData = std::make_unique<std::vector<uint8_t>>(size);
auto content = Azure::Core::IO::MemoryBodyStream(*rawData);
m_blobClient->Upload(content);
m_blobClientSas = std::make_unique<Azure::Storage::Blobs::BlockBlobClient>(
m_blobClient->GetUrl() + GetSasToken());
}
/**
* @brief Define the test
*
*/
void Run(Azure::Core::Context const&) override
{
m_blobClientSas->DownloadTo(m_downloadBuffer->data(), m_downloadBuffer->size());
}
/**
* @brief Define the test options for the test.
*
* @return The list of test options.
*/
std::vector<Azure::Perf::TestOption> GetTestOptions() override
{
// TODO: Merge with base options
return {{"Size", {"--size"}, "Size of payload (in bytes)", 1, true}};
}
/**
* @brief Get the static Test Metadata for the test.
*
* @return Azure::Perf::TestMetadata describing the test.
*/
static Azure::Perf::TestMetadata GetTestMetadata()
{
return {"DownloadBlobSas", "Download a blob.", [](Azure::Perf::TestOptions options) {
return std::make_unique<Azure::Storage::Blobs::Test::DownloadBlobSas>(options);
}};
}
};
}}}} // namespace Azure::Storage::Blobs::Test

View File

@ -0,0 +1,117 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief Test the performance of downloading a block blob using SaS token and with the http core
* pipeline directly.
*
*/
#pragma once
#include <azure/core/http/curl_transport.hpp>
#include <azure/core/io/body_stream.hpp>
#include <azure/perf.hpp>
#include "azure/storage/blobs/test/blob_base_test.hpp"
#include <iostream>
#include <memory>
#include <string>
#include <vector>
namespace Azure { namespace Storage { namespace Blobs { namespace Test {
/**
* @brief A test to measure downloading a blob using SaS token and with the http core pipeline
* directly.
*
*/
class DownloadBlobWithPipelineOnly : public Azure::Storage::Blobs::Test::BlobsTest {
private:
std::unique_ptr<std::vector<uint8_t>> m_downloadBuffer;
std::unique_ptr<Azure::Core::Http::_internal::HttpPipeline> m_pipeline;
std::unique_ptr<Azure::Core::Http::Request> m_request;
public:
/**
* @brief Construct a new DownloadBlobWithPipelineOnly test.
*
* @param options The test options.
*/
DownloadBlobWithPipelineOnly(Azure::Perf::TestOptions options) : BlobsTest(options) {}
/**
* @brief The size to upload on setup is defined by a mandatory parameter.
*
*/
void Setup() override
{
// Call base to create blob client
BlobsTest::Setup();
long size = m_options.GetMandatoryOption<long>("Size");
bool bufferResponse = m_options.GetMandatoryOption<bool>("Buffer");
m_downloadBuffer = std::make_unique<std::vector<uint8_t>>(size);
auto rawData = std::make_unique<std::vector<uint8_t>>(size);
auto content = Azure::Core::IO::MemoryBodyStream(*rawData);
m_blobClient->Upload(content);
auto requestUrl = m_blobClient->GetUrl() + GetSasToken();
m_request = std::make_unique<Azure::Core::Http::Request>(
Azure::Core::Http::HttpMethod::Get, Azure::Core::Url(requestUrl), bufferResponse);
Azure::Core::_internal::ClientOptions options;
std::vector<std::unique_ptr<Azure::Core::Http::Policies::HttpPolicy>> perRetry;
std::vector<std::unique_ptr<Azure::Core::Http::Policies::HttpPolicy>> perOperation;
m_pipeline = std::make_unique<Azure::Core::Http::_internal::HttpPipeline>(
options, "perfTest", "x.x", std::move(perRetry), std::move(perOperation));
}
/**
* @brief Define the test
*
*/
void Run(Azure::Core::Context const& context) override
{
// Transport policy resolved the buffer option. If buffer is ON on the request, the response
// will contain the payload directly. When it is OFF, the response will contain the stream to
// the network.
auto response = m_pipeline->Send(*m_request, context);
}
/**
* @brief Define the test options for the test.
*
* @return The list of test options.
*/
std::vector<Azure::Perf::TestOption> GetTestOptions() override
{
// TODO: Merge with base options
return {
{"Size", {"--size"}, "Size of payload (in bytes)", 1, true},
{"Buffer", {"--buffer"}, "Whether to buffer the response", 1, true}};
}
/**
* @brief Get the static Test Metadata for the test.
*
* @return Azure::Perf::TestMetadata describing the test.
*/
static Azure::Perf::TestMetadata GetTestMetadata()
{
return {
"DownloadBlobWithPipelineOnly",
"Download a blob using the curl transport adapter directly. No SDK layer.",
[](Azure::Perf::TestOptions options) {
return std::make_unique<Azure::Storage::Blobs::Test::DownloadBlobWithPipelineOnly>(
options);
}};
}
};
}}}} // namespace Azure::Storage::Blobs::Test

View File

@ -0,0 +1,116 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT
/**
* @file
* @brief Test the performance of downloading a block blob using SaS token and with transport
* adapter directly.
*
*/
#pragma once
#include <azure/core/http/curl_transport.hpp>
#include <azure/core/io/body_stream.hpp>
#include <azure/perf.hpp>
#include "azure/storage/blobs/test/blob_base_test.hpp"
#include <iostream>
#include <memory>
#include <string>
#include <vector>
namespace Azure { namespace Storage { namespace Blobs { namespace Test {
/**
* @brief A test to measure downloading a blob using SaS token and with transport adapter
* directly.
*
*/
class DownloadBlobWithTransportOnly : public Azure::Storage::Blobs::Test::BlobsTest {
private:
std::unique_ptr<std::vector<uint8_t>> m_downloadBuffer;
std::unique_ptr<Azure::Core::Http::CurlTransport> m_curlTransport;
bool m_bufferResponse = false;
std::unique_ptr<Azure::Core::Http::Request> m_request;
public:
/**
* @brief Construct a new DownloadBlobWithTransportOnly test.
*
* @param options The test options.
*/
DownloadBlobWithTransportOnly(Azure::Perf::TestOptions options) : BlobsTest(options) {}
/**
* @brief The size to upload on setup is defined by a mandatory parameter.
*
*/
void Setup() override
{
// Call base to create blob client
BlobsTest::Setup();
long size = m_options.GetMandatoryOption<long>("Size");
m_bufferResponse = m_options.GetMandatoryOption<bool>("Buffer");
m_downloadBuffer = std::make_unique<std::vector<uint8_t>>(size);
auto rawData = std::make_unique<std::vector<uint8_t>>(size);
auto content = Azure::Core::IO::MemoryBodyStream(*rawData);
m_blobClient->Upload(content);
auto requestUrl = m_blobClient->GetUrl() + GetSasToken();
m_curlTransport = std::make_unique<Azure::Core::Http::CurlTransport>();
m_request = std::make_unique<Azure::Core::Http::Request>(
Azure::Core::Http::HttpMethod::Get, Azure::Core::Url(requestUrl), m_bufferResponse);
}
/**
* @brief Define the test
*
*/
void Run(Azure::Core::Context const& context) override
{
auto response = m_curlTransport->Send(*m_request, context);
if (m_bufferResponse)
{
// if test request the response stream to be read completely.
*m_downloadBuffer = response->ExtractBodyStream()->ReadToEnd();
}
}
/**
* @brief Define the test options for the test.
*
* @return The list of test options.
*/
std::vector<Azure::Perf::TestOption> GetTestOptions() override
{
// TODO: Merge with base options
return {
{"Size", {"--size"}, "Size of payload (in bytes)", 1, true},
{"Buffer", {"--buffer"}, "Whether to buffer the response", 1, true}};
}
/**
* @brief Get the static Test Metadata for the test.
*
* @return Azure::Perf::TestMetadata describing the test.
*/
static Azure::Perf::TestMetadata GetTestMetadata()
{
return {
"DownloadBlobWithTransportOnly",
"Download a blob using the curl transport adapter directly. No SDK layer.",
[](Azure::Perf::TestOptions options) {
return std::make_unique<Azure::Storage::Blobs::Test::DownloadBlobWithTransportOnly>(
options);
}};
}
};
}}}} // namespace Azure::Storage::Blobs::Test

View File

@ -3,7 +3,14 @@
#include <azure/perf.hpp>
#include "azure/storage/blobs/test/download_blob_from_sas.hpp"
#include "azure/storage/blobs/test/download_blob_pipeline_only.hpp"
#include "azure/storage/blobs/test/download_blob_test.hpp"
#if defined(BUILD_CURL_HTTP_TRANSPORT_ADAPTER)
#include "azure/storage/blobs/test/download_blob_transport_only.hpp"
#endif
#include "azure/storage/blobs/test/list_blob_test.hpp"
#include "azure/storage/blobs/test/upload_blob_test.hpp"
@ -11,10 +18,17 @@ int main(int argc, char** argv)
{
// Create the test list
std::vector<Azure::Perf::TestMetadata> tests{
Azure::Storage::Blobs::Test::DownloadBlob::GetTestMetadata(),
Azure::Storage::Blobs::Test::UploadBlob::GetTestMetadata(),
Azure::Storage::Blobs::Test::ListBlob::GetTestMetadata()};
std::vector<Azure::Perf::TestMetadata> tests
{
Azure::Storage::Blobs::Test::DownloadBlob::GetTestMetadata(),
Azure::Storage::Blobs::Test::UploadBlob::GetTestMetadata(),
Azure::Storage::Blobs::Test::ListBlob::GetTestMetadata(),
Azure::Storage::Blobs::Test::DownloadBlobSas::GetTestMetadata(),
#if defined(BUILD_CURL_HTTP_TRANSPORT_ADAPTER)
Azure::Storage::Blobs::Test::DownloadBlobWithTransportOnly::GetTestMetadata(),
#endif
Azure::Storage::Blobs::Test::DownloadBlobWithPipelineOnly::GetTestMetadata()
};
Azure::Perf::Program::Run(Azure::Core::Context::ApplicationContext, tests, argc, argv);