Azure Storage-resources in C++ weergeven

Het vermelden van bewerkingen is essentieel voor veel ontwikkelscenario's met Azure Storage. In dit artikel wordt beschreven hoe u objecten in Azure Storage het efficiëntst opsommen met behulp van de api's die worden vermeld in de Microsoft Azure Storage-clientbibliotheek voor C++.

Notitie

Deze handleiding is gericht op de Azure Storage-clientbibliotheek voor C++ versie 2.x, die beschikbaar is via NuGet of GitHub.

De Storage-clientbibliotheek biedt verschillende methoden om objecten in Azure Storage weer te geven of er query's op uit te voeren. In dit artikel worden de volgende scenario's behandeld:

  • Containers in een account weergeven
  • Blobs weergeven in een container of virtuele blobmap
  • Wachtrijen in een account weergeven
  • Tabellen in een account weergeven
  • Query's uitvoeren op entiteiten in een tabel

Elk van deze methoden wordt weergegeven met behulp van verschillende overbelastingen voor verschillende scenario's.

Asynchroon versus synchroon

Omdat de Storage-clientbibliotheek voor C++ is gebouwd op de C++ REST-bibliotheek, ondersteunen we inherent asynchrone bewerkingen met behulp van pplx::task. Bijvoorbeeld:

pplx::task<list_blob_item_segment> list_blobs_segmented_async(continuation_token& token) const;

Synchrone bewerkingen verpakken de bijbehorende asynchrone bewerkingen:

list_blob_item_segment list_blobs_segmented(const continuation_token& token) const
{
    return list_blobs_segmented_async(token).get();
}

Als u met meerdere threadtoepassingen of -services werkt, raden we u aan de asynchrone API's rechtstreeks te gebruiken in plaats van een thread te maken om de synchronisatie-API's aan te roepen, wat een aanzienlijke invloed heeft op uw prestaties.

Gesegmenteerde vermelding

Voor de schaal van cloudopslag is een gesegmenteerde lijst vereist. U kunt bijvoorbeeld meer dan een miljoen blobs in een Azure-blobcontainer of meer dan een miljard entiteiten in een Azure-tabel hebben. Dit zijn geen theoretische getallen, maar echte klantgebruikscases.

Het is daarom niet praktisch om alle objecten in één antwoord weer te geven. In plaats daarvan kunt u objecten weergeven met behulp van paging. Elk van de lijst-API's heeft een gesegmenteerde overbelasting.

Het antwoord voor een gesegmenteerde vermeldingsbewerking omvat:

  • _segment, die de set resultaten bevat die wordt geretourneerd voor één aanroep naar de vermeldings-API.
  • continuation_token, die wordt doorgegeven aan de volgende aanroep om de volgende pagina met resultaten op te halen. Wanneer er geen resultaten meer zijn om te retourneren, is het vervolgtoken null.

Een typische aanroep om alle blobs in een container weer te geven, kan er bijvoorbeeld uitzien als het volgende codefragment. De code is beschikbaar in onze voorbeelden:

// List blobs in the blob container
azure::storage::continuation_token token;
do
{
    azure::storage::list_blob_item_segment segment = container.list_blobs_segmented(token);
    for (auto it = segment.results().cbegin(); it != segment.results().cend(); ++it)
{
    if (it->is_blob())
    {
        process_blob(it->as_blob());
    }
    else
    {
        process_directory(it->as_directory());
    }
}

    token = segment.continuation_token();
}
while (!token.empty());

Houd er rekening mee dat het aantal resultaten dat op een pagina wordt geretourneerd, kan worden bepaald door de parameter max_results in de overbelasting van elke API, bijvoorbeeld:

list_blob_item_segment list_blobs_segmented(const utility::string_t& prefix, bool use_flat_blob_listing,
    blob_listing_details::values includes, int max_results, const continuation_token& token,
    const blob_request_options& options, operation_context context)

Als u de parameter max_results niet opgeeft, wordt de standaard maximumwaarde van maximaal 5000 resultaten geretourneerd op één pagina.

Houd er ook rekening mee dat een query op Azure Table Storage geen records of minder records kan retourneren dan de waarde van de parameter max_results die u hebt opgegeven, zelfs als het vervolgtoken niet leeg is. Een reden kan zijn dat de query niet binnen vijf seconden kon worden voltooid. Zolang het vervolgtoken niet leeg is, moet de query worden voortgezet en mag uw code niet de grootte van de segmentresultaten aannemen.

Het aanbevolen coderingspatroon voor de meeste scenario's is gesegmenteerde vermelding, die expliciete voortgang van het vermelden of uitvoeren van query's biedt, en hoe de service op elke aanvraag reageert. Met name voor C++-toepassingen of -services kan een lagere controle over de voortgang van de vermelding het geheugen en de prestaties helpen.

Greedy vermelding

Eerdere versies van de Storage-clientbibliotheek voor C++ (versie 0.5.0 Preview en eerder) bevatten niet-gesegmenteerde vermeldings-API's voor tabellen en wachtrijen, zoals in het volgende voorbeeld:

std::vector<cloud_table> list_tables(const utility::string_t& prefix) const;
std::vector<table_entity> execute_query(const table_query& query) const;
std::vector<cloud_queue> list_queues() const;

Deze methoden zijn geïmplementeerd als wrappers van gesegmenteerde API's. Voor elk antwoord van gesegmenteerde vermeldingen heeft de code de resultaten toegevoegd aan een vector en alle resultaten geretourneerd nadat de volledige containers zijn gescand.

Deze benadering werkt mogelijk wanneer het opslagaccount of de tabel een klein aantal objecten bevat. Met een toename van het aantal objecten kan het benodigde geheugen echter onbeperkt toenemen, omdat alle resultaten in het geheugen bleven. Een vermeldingsbewerking kan erg lang duren, waarbij de aanroeper geen informatie had over de voortgang.

Deze API's met greedy vermeldingen in de SDK bestaan niet in C#, Java of de JavaScript-Node.js-omgeving. Om mogelijke problemen met het gebruik van deze greedy API's te voorkomen, hebben we ze verwijderd in versie 0.6.0 Preview.

Als uw code deze hebzuchtige API's aanroept:

std::vector<azure::storage::table_entity> entities = table.execute_query(query);
for (auto it = entities.cbegin(); it != entities.cend(); ++it)
{
    process_entity(*it);
}

Vervolgens moet u uw code wijzigen om de API's voor gesegmenteerde vermeldingen te gebruiken:

azure::storage::continuation_token token;
do
{
    azure::storage::table_query_segment segment = table.execute_query_segmented(query, token);
    for (auto it = segment.results().cbegin(); it != segment.results().cend(); ++it)
    {
        process_entity(*it);
    }

    token = segment.continuation_token();
} while (!token.empty());

Door de parameter max_results van het segment op te geven, kunt u een balans vinden tussen het aantal aanvragen en het geheugengebruik om te voldoen aan prestatieoverwegingen voor uw toepassing.

Als u api's voor gesegmenteerde vermeldingen gebruikt, maar de gegevens in een lokale verzameling in een 'hebzuchtige' stijl opslaat, raden we u ook ten zeerste aan uw code te herstructureren om het opslaan van gegevens in een lokale verzameling zorgvuldig op schaal af te handelen.

Luie vermelding

Hoewel hebzuchtige vermelding potentiële problemen heeft veroorzaakt, is het handig als er niet te veel objecten in de container zijn.

Als u ook C# of Oracle Java SDK's gebruikt, moet u bekend zijn met het programmeermodel Enumerable, dat een luie lijst biedt, waarbij de gegevens bij een bepaalde offset alleen worden opgehaald als dat nodig is. In C++ biedt de op iterator gebaseerde sjabloon ook een vergelijkbare benadering.

Een typische lazy listing-API, met list_blobs als voorbeeld, ziet er als volgt uit:

list_blob_item_iterator list_blobs() const;

Een typisch codefragment dat gebruikmaakt van het luie vermeldingspatroon kan er als volgt uitzien:

// List blobs in the blob container
azure::storage::list_blob_item_iterator end_of_results;
for (auto it = container.list_blobs(); it != end_of_results; ++it)
{
    if (it->is_blob())
    {
        process_blob(it->as_blob());
    }
    else
    {
        process_directory(it->as_directory());
    }
}

Houd er rekening mee dat luie vermelding alleen beschikbaar is in de synchrone modus.

Vergeleken met greedy vermeldingen haalt luie vermelding alleen gegevens op wanneer dat nodig is. Op de achtergrond worden alleen gegevens opgehaald uit Azure Storage wanneer de volgende iterator naar het volgende segment gaat. Daarom wordt het geheugengebruik beheerd met een begrensde grootte en is de bewerking snel.

Luie API's zijn opgenomen in de Storage-clientbibliotheek voor C++ in versie 2.2.0.

Conclusie

In dit artikel hebben we verschillende overloads besproken voor het weergeven van API's voor verschillende objecten in de Storage-clientbibliotheek voor C++ . Samenvatting:

  • Asynchrone API's worden sterk aanbevolen in scenario's met meerdere threads.
  • Voor de meeste scenario's wordt een gesegmenteerde vermelding aanbevolen.
  • Luie vermelding wordt in de bibliotheek aangeboden als een handige wrapper in synchrone scenario's.
  • Greedy vermelding wordt niet aanbevolen en is verwijderd uit de bibliotheek.

Volgende stappen

Zie de volgende resources voor meer informatie over Azure Storage en clientbibliotheek voor C++.