Udostępnij za pośrednictwem


Generowanie listy zasobów usługi Azure Storage w języku C++

Wyświetlanie listy operacji jest kluczem do wielu scenariuszy programowania w usłudze Azure Storage. W tym artykule opisano sposób najefektywniejszego wyliczania obiektów w usłudze Azure Storage przy użyciu interfejsów API list dostępnych w bibliotece klienta usługi Microsoft Azure Storage dla języka C++.

Uwaga

Ten przewodnik jest przeznaczony dla biblioteki klienta usługi Azure Storage dla języka C++ w wersji 2.x, która jest dostępna za pośrednictwem narzędzia NuGet lub GitHub.

Biblioteka klienta usługi Storage udostępnia różne metody wyświetlania listy obiektów lub wykonywania zapytań w usłudze Azure Storage. Ten artykuł dotyczy następujących scenariuszy:

  • Wyświetlanie listy kontenerów na koncie
  • Wyświetlanie listy obiektów blob w kontenerze lub katalogu obiektów blob wirtualnych
  • Wyświetlanie listy kolejek na koncie
  • Wyświetlanie listy tabel na koncie
  • Wykonywanie zapytań o jednostki w tabeli

Każda z tych metod jest wyświetlana przy użyciu różnych przeciążeń dla różnych scenariuszy.

Asynchroniczne a synchroniczne

Ponieważ biblioteka klienta magazynu dla języka C++ jest oparta na bibliotece REST języka C++, z założenia obsługujemy operacje asynchroniczne przy użyciu pliku pplx::task. Na przykład:

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

Operacje synchroniczne opakowuje odpowiednie operacje asynchroniczne:

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

Jeśli pracujesz z wieloma aplikacjami lub usługami wątkowymi, zalecamy bezpośrednie używanie asynchronicznych interfejsów API zamiast tworzenia wątku w celu wywołania interfejsów API synchronizacji, co znacząco wpływa na wydajność.

Lista segmentowana

Skala magazynu w chmurze wymaga segmentowanej listy. Na przykład w kontenerze obiektów blob platformy Azure można mieć ponad milion obiektów blob lub ponad miliard jednostek w tabeli platformy Azure. Nie są to liczby teoretyczne, ale rzeczywiste przypadki użycia klientów.

Dlatego niepraktyczne jest wyświetlanie listy wszystkich obiektów w pojedynczej odpowiedzi. Zamiast tego można wyświetlić listę obiektów przy użyciu stronicowania. Każdy z interfejsów API listy ma przeciążenie segmentowane .

Odpowiedź na operację listy segmentowanej obejmuje:

  • _segment, który zawiera zestaw wyników zwróconych dla pojedynczego wywołania interfejsu API listy.
  • continuation_token, który jest przekazywany do następnego wywołania w celu uzyskania następnej strony wyników. Jeśli nie ma więcej wyników do zwrócenia, token kontynuacji ma wartość null.

Na przykład typowe wywołanie listy wszystkich obiektów blob w kontenerze może wyglądać podobnie do poniższego fragmentu kodu. Kod jest dostępny w naszych przykładach:

// 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());

Należy pamiętać, że liczba wyników zwróconych na stronie może być kontrolowana przez parametr max_results w przeciążeniu każdego interfejsu API, na przykład:

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)

Jeśli nie określisz parametru max_results, zostanie zwrócona domyślna maksymalna wartość do 5000 wyników na jednej stronie.

Należy również pamiętać, że zapytanie względem usługi Azure Table Storage może nie zwracać żadnych rekordów lub mniejszej liczby rekordów niż wartość określonego parametru max_results , nawet jeśli token kontynuacji nie jest pusty. Jednym z powodów może być to, że zapytanie nie może zakończyć się w ciągu pięciu sekund. Jeśli token kontynuacji nie jest pusty, zapytanie powinno kontynuować, a kod nie powinien zakładać rozmiaru wyników segmentu.

Zalecanym wzorcem kodowania dla większości scenariuszy jest lista segmentowana, która zapewnia jawny postęp wyświetlania listy lub wykonywania zapytań oraz sposób, w jaki usługa odpowiada na każde żądanie. Szczególnie w przypadku aplikacji lub usług języka C++ kontrola na niższym poziomie postępu wyświetlania listy może pomóc w kontrolowaniu pamięci i wydajności.

Chciwy list

Starsze wersje biblioteki klienta magazynu dla języka C++ (wersje 0.5.0 (wersja zapoznawcza i starsza) zawierały niesegmentowane interfejsy API list dla tabel i kolejek, jak w poniższym przykładzie:

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;

Te metody zostały zaimplementowane jako otoki segmentowanych interfejsów API. Dla każdej odpowiedzi na listę segmentowaną kod dodał wyniki do wektora i zwrócił wszystkie wyniki po zeskanowaniu pełnych kontenerów.

Takie podejście może działać, gdy konto magazynu lub tabela zawiera niewielką liczbę obiektów. Jednak wraz ze wzrostem liczby obiektów wymagana pamięć może wzrosnąć bez limitu, ponieważ wszystkie wyniki pozostały w pamięci. Jedna operacja wyświetlania listy może zająć bardzo dużo czasu, podczas którego obiekt wywołujący nie miał informacji o jego postępie.

Te chciwy list interfejsów API w zestawie SDK nie istnieją w języku C#, Java ani w środowisku Node.js JavaScript. Aby uniknąć potencjalnych problemów z używaniem tych chciwych interfejsów API, usunęliśmy je w wersji 0.6.0 (wersja zapoznawcza).

Jeśli kod wywołuje te chciwe interfejsy API:

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

Następnie należy zmodyfikować kod tak, aby używał interfejsów API listy segmentowanej:

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());

Określając parametr max_results segmentu, można równoważyć liczbę żądań i użycia pamięci, aby spełnić wymagania dotyczące wydajności aplikacji.

Ponadto jeśli używasz interfejsów API list segmentowanych, ale dane są przechowywane w kolekcji lokalnej w stylu "chciwości", zdecydowanie zalecamy również refaktoryzowanie kodu w celu obsługi przechowywania danych w lokalnej kolekcji na dużą skalę.

Lista z opóźnieniem

Mimo że chciwy list wzbudził potencjalne problemy, wygodne jest, jeśli nie ma zbyt wielu obiektów w kontenerze.

Jeśli używasz również zestawów SDK języka C# lub Oracle Java, musisz zapoznać się z modelem programowania Wyliczalnym, który oferuje listę w stylu leniwym, gdzie dane z pewnym przesunięciem są pobierane tylko wtedy, gdy jest to wymagane. W języku C++szablon oparty na iteratorze zapewnia również podobne podejście.

Typowy interfejs API z opóźnieniem, używając list_blobs jako przykładu, wygląda następująco:

list_blob_item_iterator list_blobs() const;

Typowy fragment kodu korzystający ze wzorca listy z opóźnieniem może wyglądać następująco:

// 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());
    }
}

Należy pamiętać, że lista z opóźnieniem jest dostępna tylko w trybie synchronicznym.

W porównaniu z chciwą listą, leniwa lista pobiera dane tylko wtedy, gdy jest to konieczne. W obszarze okładek pobiera ona dane z usługi Azure Storage tylko wtedy, gdy następny iterator przechodzi do następnego segmentu. W związku z tym użycie pamięci jest kontrolowane przy użyciu ograniczonego rozmiaru, a operacja jest szybka.

Interfejsy API listy z opóźnieniem znajdują się w bibliotece klienta magazynu dla języka C++ w wersji 2.2.0.

Podsumowanie

W tym artykule omówiliśmy różne przeciążenia dotyczące wyświetlania listy interfejsów API dla różnych obiektów w bibliotece klienta usługi Storage dla języka C++. Podsumowując:

  • Interfejsy API asynchroniczne są zdecydowanie zalecane w wielu scenariuszach wątkowych.
  • Lista segmentowana jest zalecana w przypadku większości scenariuszy.
  • Lista z opóźnieniem jest udostępniana w bibliotece jako wygodna otoka w scenariuszach synchronicznych.
  • Chciwość listy nie jest zalecana i została usunięta z biblioteki.

Następne kroki

Aby uzyskać więcej informacji na temat usługi Azure Storage i biblioteki klienta dla języka C++, zobacz następujące zasoby.