Listar Recursos do Armazenamento do Microsoft Azure em C++
As operações de listagem são fundamentais para muitos cenários de desenvolvimento com o Armazenamento do Azure. Este artigo descreve como enumerar objetos no Armazenamento do Azure de forma mais eficiente usando as APIs de listagem fornecidas na Biblioteca de Cliente de Armazenamento do Microsoft Azure para C++.
Nota
Este guia destina-se à Biblioteca de Cliente de Armazenamento do Azure para C++ versão 2.x, que está disponível através do NuGet ou do GitHub.
A Biblioteca de Cliente de Armazenamento fornece uma variedade de métodos para listar ou consultar objetos no Armazenamento do Azure. Este artigo aborda os seguintes cenários:
- Listar contêineres em uma conta
- Listar blobs em um contêiner ou diretório de blob virtual
- Listar filas em uma conta
- Listar tabelas em uma conta
- Entidades de consulta em uma tabela
Cada um desses métodos é mostrado usando sobrecargas diferentes para diferentes cenários.
Assíncrono versus síncrono
Como a biblioteca de cliente de armazenamento para C++ é criada sobre a biblioteca REST do C++, oferecemos suporte inerente a operações assíncronas usando pplx::task. Por exemplo:
pplx::task<list_blob_item_segment> list_blobs_segmented_async(continuation_token& token) const;
As operações síncronas encapsulam as operações assíncronas correspondentes:
list_blob_item_segment list_blobs_segmented(const continuation_token& token) const
{
return list_blobs_segmented_async(token).get();
}
Se você estiver trabalhando com vários aplicativos ou serviços de threading, recomendamos que use as APIs assíncronas diretamente em vez de criar um thread para chamar as APIs de sincronização, o que afeta significativamente seu desempenho.
Listagem segmentada
A escala do armazenamento em nuvem requer listagem segmentada. Por exemplo, você pode ter mais de um milhão de blobs em um contêiner de blob do Azure ou mais de um bilhão de entidades em uma Tabela do Azure. Estes não são números teóricos, mas casos reais de uso do cliente.
Portanto, é impraticável listar todos os objetos em uma única resposta. Em vez disso, você pode listar objetos usando paginação. Cada uma das APIs de listagem tem uma sobrecarga segmentada .
A resposta para uma operação de listagem segmentada inclui:
- _segment, que contém o conjunto de resultados retornados para uma única chamada para a API de listagem.
- continuation_token, que é passado para a próxima chamada, a fim de obter a próxima página de resultados. Quando não houver mais resultados para retornar, o token de continuação será nulo.
Por exemplo, uma chamada típica para listar todos os blobs em um contêiner pode se parecer com o trecho de código a seguir. O código está disponível em nossos exemplos:
// 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());
Observe que o número de resultados retornados em uma página pode ser controlado pelo parâmetro max_results na sobrecarga de cada API, por exemplo:
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)
Se você não especificar o parâmetro max_results , o valor máximo padrão de até 5000 resultados será retornado em uma única página.
Observe também que uma consulta no armazenamento de Tabela do Azure pode retornar nenhum registro ou menos registros do que o valor do parâmetro max_results que você especificou, mesmo que o token de continuação não esteja vazio. Um motivo pode ser que a consulta não pôde ser concluída em cinco segundos. Contanto que o token de continuação não esteja vazio, a consulta deve continuar e seu código não deve assumir o tamanho dos resultados do segmento.
O padrão de codificação recomendado para a maioria dos cenários é a listagem segmentada, que fornece o progresso explícito da listagem ou consulta e como o serviço responde a cada solicitação. Particularmente para aplicativos ou serviços C++, o controle de nível inferior do progresso da listagem pode ajudar a controlar a memória e o desempenho.
Listagem gananciosa
As versões anteriores da Biblioteca de Cliente de Armazenamento para C++ (versões 0.5.0 Preview e anteriores) incluíam APIs de listagem não segmentadas para tabelas e filas, como no exemplo a seguir:
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;
Esses métodos foram implementados como wrappers de APIs segmentadas. Para cada resposta de listagem segmentada, o código anexou os resultados a um vetor e retornou todos os resultados depois que os contêineres completos foram verificados.
Essa abordagem pode funcionar quando a conta ou tabela de armazenamento contém um pequeno número de objetos. No entanto, com um aumento no número de objetos, a memória necessária poderia aumentar sem limite, porque todos os resultados permaneceram na memória. Uma operação de listagem pode levar muito tempo, durante a qual o chamador não tinha informações sobre seu progresso.
Essas APIs de listagem gananciosas no SDK não existem em C#, Java ou no ambiente JavaScript Node.js. Para evitar os possíveis problemas de usar essas APIs gananciosas, nós as removemos na versão 0.6.0 Preview.
Se o seu código estiver chamando essas APIs gananciosas:
std::vector<azure::storage::table_entity> entities = table.execute_query(query);
for (auto it = entities.cbegin(); it != entities.cend(); ++it)
{
process_entity(*it);
}
Em seguida, você deve modificar seu código para usar as APIs de listagem segmentada:
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());
Especificando o parâmetro max_results do segmento, você pode equilibrar entre o número de solicitações e o uso de memória para atender às considerações de desempenho do seu aplicativo.
Além disso, se você estiver usando APIs de listagem segmentadas, mas armazenar os dados em uma coleção local em um estilo "ganancioso", também recomendamos que você refatore seu código para lidar com o armazenamento de dados em uma coleção local cuidadosamente em escala.
Listagem preguiçosa
Embora a listagem gananciosa tenha levantado possíveis problemas, é conveniente se não houver muitos objetos no contêiner.
Se você também estiver usando C# ou Oracle Java SDKs, você deve estar familiarizado com o modelo de programação enumerável, que oferece uma listagem de estilo preguiçoso, onde os dados em um determinado deslocamento só são buscados se forem necessários. Em C++, o modelo baseado em iterador também fornece uma abordagem semelhante.
Uma API de listagem preguiçosa típica, usando list_blobs como exemplo, tem esta aparência:
list_blob_item_iterator list_blobs() const;
Um trecho de código típico que usa o padrão de listagem preguiçoso pode ter esta aparência:
// 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());
}
}
Observe que a listagem preguiçosa só está disponível no modo síncrono.
Em comparação com a listagem gananciosa, a listagem preguiçosa busca dados apenas quando necessário. Sob as capas, ele busca dados do Armazenamento do Azure somente quando o próximo iterador se move para o próximo segmento. Portanto, o uso de memória é controlado com um tamanho limitado e a operação é rápida.
APIs de listagem lenta estão incluídas na biblioteca de cliente de armazenamento para C++ na versão 2.2.0.
Conclusão
Neste artigo, discutimos diferentes sobrecargas para listar APIs para vários objetos na Biblioteca de Cliente de Armazenamento para C++ . Para resumir:
- As APIs assíncronas são altamente recomendadas em vários cenários de threading.
- A listagem segmentada é recomendada para a maioria dos cenários.
- A listagem lenta é fornecida na biblioteca como um wrapper conveniente em cenários síncronos.
- Listagem gananciosa não é recomendada e foi removida da biblioteca.
Próximos passos
Para obter mais informações sobre o Armazenamento do Azure e a Biblioteca de Clientes para C++, consulte os recursos a seguir.
- Como usar o armazenamento de Blob a partir de C++
- Como usar o armazenamento de tabela do C++
- Como usar o armazenamento em fila a partir de C++
- Documentação da Biblioteca de Cliente de Armazenamento do Azure para API C++.
- Azure Storage Team Blog (Blogue da Equipa do Armazenamento do Azure)
- Documentação do Armazenamento do Azure