Melhores práticas para o SDK do .NET do Azure Cosmos DB

APLICA-SE A: NoSQL

Este artigo mostra as melhores práticas para usar o SDK do .NET do Azure Cosmos DB. Seguir essas práticas ajudará a melhorar a latência, a disponibilidade e o desempenho geral.

Assista ao vídeo abaixo para saber mais sobre como usar o SDK do .NET com um engenheiro do Azure Cosmos DB!

Lista de verificação

Verificado Assunto Detalhes/links
Versão do SDK Sempre use a versão mais recente disponível do SDK do Azure Cosmos DB para obter o desempenho ideal.
Cliente Singleton Use uma instância única de CosmosClient pelo tempo de vida do seu aplicativo para melhor desempenho.
Regiões Execute sempre que for possível seu aplicativo na mesma região do Azure da sua conta do Azure Cosmos DB para reduzir a latência. Habilita 2 a 4 regiões e replique suas contas em várias regiões para melhor disponibilidade. Para cargas de trabalho de produção, habilite o failover gerenciado pelo serviço. Na ausência dessa configuração, a conta passará por perda de disponibilidade de gravação durante toda a interrupção da região de gravação, pois o failover manual não funcionará devido à falta de conectividade da região. Para saber como adicionar várias regiões com o SDK do .NET, acesse aqui
Disponibilidade e failovers Defina ApplicationPreferredRegions ou ApplicationRegion no SDK v3, e PreferredLocations no SDK v2 usando a lista de regiões preferenciais. Durante failovers, as operações de gravação são enviadas à região de gravação atual e todas as leituras são enviadas à primeira região da sua lista de regiões preferenciais. Para obter mais informações sobre a mecânica do failover regional, confira o guia de solução de problemas de disponibilidade.
CPU Você poderá ter problemas de conectividade/disponibilidade devido à falta de recursos no computador cliente. Monitore o uso da CPU em nós que executam o cliente do Azure Cosmos DB e escale verticalmente/horizontalmente se o uso estiver elevado.
Hosting Para melhor desempenho, use processo de host do Windows 64-bit sempre que possível. Para as cargas de trabalho de produção sensíveis à latência de modo direto, recomendamos altamente o uso de VMs de pelo menos 4 núcleos e 8 GB de memória, sempre que possível.
Modos de conectividade Use o modo Direto para ter o melhor desempenho. Para obter instruções, consulte a documentação do SDK v3 ou a documentação do SDK v2.
Rede Se usar uma máquina virtual, para executar seu aplicativo, habilite a Rede Acelerada na sua VM para ajudar com gargalos devido ao alto tráfego e reduzir a latência ou a tremulação da CPU. Talvez você também queira considerar o uso de uma máquina virtual topo de linha em que o uso máximo da CPU está abaixo de 70%.
Esgotamento de porta efêmera Para conexões esparsas ou esporádicas, definimos IdleConnectionTimeout e PortReuseMode para PrivatePortPool. A propriedade IdleConnectionTimeout ajuda a controlar o tempo após o qual as conexões não usadas são fechadas. Isso reduzirá o número de conexões não usadas. Por padrão, as conexões ociosas são mantidas abertas indefinidamente. O valor definido precisa ser maior ou igual a 10 minutos. Recomendamos valores entre 20 minutos e 24 horas. A propriedade PortReuseMode permite que o SDK use um pequeno pool de portas efêmeras para diferentes pontos de extremidade de destino do Azure Cosmos DB.
Usar Async/Await Evitar chamadas de bloqueio: Task.Result, Task.Wait e Task.GetAwaiter().GetResult(). Toda a pilha de chamadas é assíncrona para se beneficiar de padrões async/await. Muitas chamadas de bloqueio síncronas levam à Privação do pool de threads e a tempos de resposta degradados.
Tempos limite de ponta a ponta Para obter tempos limite de ponta a ponta, você precisará usar os parâmetros RequestTimeout e CancellationToken. Para obter mais detalhes, visite nosso guia de solução de problemas de tempo limite.
Lógica de repetição Para obter mais informações sobre quais erros tentar novamente e quais são repetidos pelos SDKs, consulte o guia de design. Para contas configuradas com várias regiões, há alguns cenários em que o SDK repetirá automaticamente em outras regiões. Para obter detalhes de implementação específicos do .NET, visite o repositório de origem do SDK.
Cache de nomes de banco de dados/coleção Recupere os nomes dos bancos de dados e coleções de configuração ou armazene-os em cache na inicialização. Chamadas como ReadDatabaseAsync ou ReadDocumentCollectionAsync e CreateDatabaseQuery ou CreateDocumentCollectionQuery resultarão em chamadas de metadados para o serviço, que consomem do limite de RU reservado pelo sistema. CreateIfNotExist também deve ser usado apenas uma vez para configurar o banco de dados. Em geral, essas operações devem ser executadas com pouca frequência.
Suporte em massa Em cenários em que talvez você não precise otimizar para latência, recomendamos habilitar o suporte em massa para despejar grandes volumes de dados.
Consultas paralelas O SDK do Azure Cosmos DB permite executar consultas em paralelo para melhorar a latência e a taxa de transferência nas consultas. Recomendamos definir a propriedade MaxConcurrency no QueryRequestsOptions para o número de partições que você tem. Se você não estiver ciente do número de partições, comece usando int.MaxValue, o que oferecerá a melhor latência. Em seguida, diminua o número até que ele se ajuste às restrições de recursos do ambiente para evitar problemas de alta utilização de CPU. Além disso, defina MaxBufferedItemCount para o número esperado de resultados retornados para limitar o número de resultados pré-buscados.
Retiradas de teste de desempenho Ao executar testes no seu aplicativo, você deve implementar retiradas em intervalos de RetryAfter. Respeitar essa retirada garante que você perca o mínimo de tempo esperando entre as tentativas.
Indexação A política de indexação do Azure Cosmos DB também permite especificar quais caminhos de documento serão incluídos ou excluídos da indexação usando os caminhos de indexação (IndexingPolicy.IncludedPaths e IndexingPolicy.ExcludedPaths). Não deixe de excluir caminhos não utilizados da indexação para gravações mais rápidas. Para obter mais informações sobre como criar índices usando o SDK, consulte dicas de desempenho do SDK do .NET v3.
Tamanho do documento A carga da solicitação para uma operação especificada está diretamente correlacionada ao tamanho do documento. Recomendamos reduzir o tamanho dos seus documentos, pois as operações em documentos grandes custam mais do que em documentos menores.
Aumentar o número de threads/tarefas Como as chamadas ao Azure Cosmos DB são feitas sobre a rede, pode ser necessário variar o grau de simultaneidade das solicitações, de forma que o aplicativo cliente aguarde um tempo mínimo entre as solicitações. Por exemplo, ao usar a biblioteca de paralelismo de tarefas do .NET, crie centenas de tarefas que leem ou gravam no Azure Cosmos DB.
Habilitar métricas de consulta Para mais registros em log das execuções de consulta de back-end, você pode ativar as métricas de consulta SQL usando o SDK do .NET. Para obter mais informações sobre como coletar Métricas de Consulta SQL, consulte Métricas de consulta e desempenho.
Registro em log de SDK Registrar Diagnóstico SDK para cenários pendentes, como exceções ou quando as solicitações vão além de uma latência esperada.
DefaultTraceListener O DefaultTraceListener apresenta problemas de desempenho em ambientes de produção que causam altos gargalos de CPU e E/S. Verifique se você está usando as versões mais recentes do SDK ou remova o DefaultTraceListener do seu aplicativo
Evite usar caracteres especiais em identificadores Alguns caracteres são restritos e não podem ser usados em alguns identificadores: '/', '\', '?', '#'. A recomendação geral é não usar caracteres especiais em identificadores como nome do banco de dados, nome da coleção, ID do item ou chave de partição para evitar qualquer comportamento inesperado.

Capturar diagnósticos

Todas as respostas no SDK, incluindo CosmosException, têm uma propriedade Diagnostics. Ela registra todas as informações relacionadas à solicitação única, incluindo se houve novas tentativas ou quaisquer falhas temporárias.

Os diagnósticos são retornados como uma cadeia de caracteres. A cadeia de caracteres muda a cada versão, à medida que é aprimorada para solucionar melhor os diferentes cenários. Com cada versão do SDK, a cadeia de caracteres terá alterações interruptivas na formatação. Não analise a cadeia de caracteres para evitar alterações interruptivas. O exemplo de código a seguir mostra como ler os logs de diagnóstico usando o SDK do .NET:

try
{
    ItemResponse<Book> response = await this.Container.CreateItemAsync<Book>(item: testItem);
    if (response.Diagnostics.GetClientElapsedTime() > ConfigurableSlowRequestTimeSpan)
    {
        // Log the response.Diagnostics.ToString() and add any additional info necessary to correlate to other logs 
    }
}
catch (CosmosException cosmosException)
{
    // Log the full exception including the stack trace with: cosmosException.ToString()
    
    // The Diagnostics can be logged separately if required with: cosmosException.Diagnostics.ToString()
}

// When using Stream APIs
ResponseMessage response = await this.Container.CreateItemStreamAsync(partitionKey, stream);
if (response.Diagnostics.GetClientElapsedTime() > ConfigurableSlowRequestTimeSpan || !response.IsSuccessStatusCode)
{
    // Log the diagnostics and add any additional info necessary to correlate to other logs with: response.Diagnostics.ToString()
}

Práticas recomendadas para conexões HTTP

O SDK do .NET usa HttpClient para executar solicitações HTTP, independentemente do modo de conectividade configurado. No Modo direto o HTTP é usado para operações de metadados e, no modo Gateway, é usado para operações de plano de dados e metadados. Um dos conceitos básicos do HttpClient é garantir que o HttpClient possa reagir às alterações de DNS em sua conta personalizando o tempo de vida da conexão em pool. Desde que as conexões em pool sejam mantidas abertas, elas não reagem às alterações de DNS. Essa configuração força as conexões em pool a serem fechadas periodicamente, garantindo que seu aplicativo reaja às alterações de DNS. Nossa recomendação é que você personalize esse valor de acordo com o modo de conectividade e a carga de trabalho para equilibrar o impacto no desempenho da criação frequente de novas conexões, com a necessidade de reagir às alterações de DNS (disponibilidade). Um valor de cinco minutos seria um bom começo que pode ser aumentado se estiver afetando o desempenho, especialmente para o Modo gateway.

Você pode injetar seu HttpClient personalizado por meio de CosmosClientOptions.HttpClientFactory, por exemplo:

// Use a Singleton instance of the SocketsHttpHandler, which you can share across any HttpClient in your application
SocketsHttpHandler socketsHttpHandler = new SocketsHttpHandler();
// Customize this value based on desired DNS refresh timer
socketsHttpHandler.PooledConnectionLifetime = TimeSpan.FromMinutes(5);

CosmosClientOptions cosmosClientOptions = new CosmosClientOptions()
{
    // Pass your customized SocketHttpHandler to be used by the CosmosClient
    // Make sure `disposeHandler` is `false`
    HttpClientFactory = () => new HttpClient(socketsHttpHandler, disposeHandler: false)
};

// Use a Singleton instance of the CosmosClient
return new CosmosClient("<connection-string>", cosmosClientOptions);

Se você usar a injeção de dependência do .NET, poderá simplificar o processo Singleton:

SocketsHttpHandler socketsHttpHandler = new SocketsHttpHandler();
// Customize this value based on desired DNS refresh timer
socketsHttpHandler.PooledConnectionLifetime = TimeSpan.FromMinutes(5);
// Registering the Singleton SocketsHttpHandler lets you reuse it across any HttpClient in your application
services.AddSingleton<SocketsHttpHandler>(socketsHttpHandler);

// Use a Singleton instance of the CosmosClient
services.AddSingleton<CosmosClient>(serviceProvider =>
{
    SocketsHttpHandler socketsHttpHandler = serviceProvider.GetRequiredService<SocketsHttpHandler>();
    CosmosClientOptions cosmosClientOptions = new CosmosClientOptions()
    {
        HttpClientFactory = () => new HttpClient(socketsHttpHandler, disposeHandler: false)
    };

    return new CosmosClient("<connection-string>", cosmosClientOptions);
});

As melhores práticas ao usar o modo Gateway

Aumente System.Net MaxConnections por host ao usar o modo Gateway. As solicitações do Azure Cosmos DB são feitas sobre HTTPS/REST ao usar o modo de gateway. Elas estão sujeitas ao limite de conexão padrão por nome de host ou endereço IP. Pode ser necessário definir MaxConnections como um valor mais alto (de 100 a 1000) para que a biblioteca de cliente possa utilizar várias conexões simultâneas com o Azure Cosmos DB. No SDK .NET 1.8.0 e posteriores, o valor padrão de ServicePointManager.DefaultConnectionLimit será 50. Para alterá-lo, defina CosmosClientOptions.GatewayModeMaxConnectionLimit como um valor mais alto.

Melhores práticas para cargas de trabalho com muita gravação

Para cargas de trabalho com cargas de criação pesadas, defina a opção de solicitação EnableContentResponseOnWrite como false. O serviço não retornará mais o recurso criado ou atualizado para o SDK. Normalmente, como o aplicativo tem o objeto que está sendo criado, ele não precisa que o serviço o retorne. Os valores de cabeçalho ainda são acessíveis, como uma carga de solicitação. Desabilitar a resposta de conteúdo pode ajudar a melhorar o desempenho, pois o SDK não precisa mais alocar memória ou serializar o corpo da resposta. Isso também reduz o uso de largura de banda da rede e ajudar ainda mais no desempenho.

Importante

A configuração de EnableContentResponseOnWrite como false também desabilitará a resposta de uma operação de gatilho.

Boas práticas para aplicativos multilocatário

Os aplicativos que distribuem o uso entre vários locatários, sendo que cada locatário é representado por um banco de dados, contêiner ou chave de partição diferentes, dentro da mesma conta do Azure Cosmos DB, devem usar uma única instância de cliente. Uma única instância de cliente pode interagir com todos os bancos de dados, contêineres e chaves de partição dentro de uma conta e usar o padrão de banco de dados individual é uma boa prática.

No entanto, quando cada locatário é representado por uma conta diferente do Azure Cosmos DB é necessário criar uma instância de cliente separada para cada conta. O padrão de banco de dados individual continua se aplicando a cada cliente (um cliente para cada conta por todo o tempo de vida do aplicativo), mas se o volume de locatários for alto, o número de clientes poderá ser difícil de gerenciar. As conexões podem aumentar além dos limites do ambiente de computação e causar problemas de conectividade.

Nesses casos, é recomendável:

  • Entender as limitações do ambiente de computação (recursos de CPU e conexão). Recomendamos o uso de VMs com pelo menos 4 núcleos e 8 GB de memória sempre que possível.
  • Com base nas limitações do ambiente de computação, determine o número de instâncias de cliente (e, portanto, o número de locatários) que uma única instância de computação pode controlar. Você pode estimar o número de conexões que serão abertas por cliente, dependendo do modo de conexão escolhido.
  • Avalie a distribuição de locatários entre todas as instâncias. Se cada instância de computação puder controlar com sucesso uma determinada quantidade limitada de locatários, o balanceamento de carga e o roteamento dos locatários para instâncias de computação diferentes permitirão uma ampliação à medida que o número de locatários aumentar.
  • Para cargas de trabalho esparsas, pense em usar um armazenamento em cache Menos Frequentemente Usado como a estrutura para manter as instâncias do cliente e descartar clientes para os locatários que não foram acessados durante um intervalo de tempo. Uma opção no .NET são as MemoryCacheEntryOptions, nas quais RegisterPostEvictionCallback pode ser usado para descartar clientes inativos e SetSlidingExpiration pode ser usado para definir o intervalo de tempo máximo para manter conexões inativas.
  • Avalie o uso do modo Gateway para reduzir o número de conexões de rede.
  • Ao usar o modo Direto, pense em ajustar o CosmosClientOptions.IdleTcpConnectionTimeout e oCosmosClientOptions.PortReuseMode na configuração do modo direto para fechar conexões não utilizadas e manter o volume de conexões sob controle.

Próximas etapas

Para obter um aplicativo de exemplo que é usado na avaliação do Azure Cosmos DB para cenários de alto desempenho em alguns computadores cliente, consulte Teste de desempenho e escala com o Azure Cosmos DB.

Para saber mais sobre como projetar seu aplicativo para escala e alto desempenho, consulte Particionamento e escala no Azure Cosmos DB.

Tentando fazer um planejamento de capacidade para uma migração para o Microsoft Azure Cosmos DB? Você pode usar informações sobre o cluster de banco de dados existente para fazer isso.