Otimizando o Desempenho no Azure Cosmos DB: Melhores Práticas e Dicas

Quando estamos trabalhando com um banco de dados, a otimização é crucial e fundamental em termos de desempenho e eficiência do aplicativo. Da mesma forma, no Azure Cosmos DB, a otimização é crucial para maximizar a eficiência, minimizar custos e garantir que seu aplicativo escale efetivamente. Abaixo estão algumas das melhores práticas com exemplos de codificação para otimizar o desempenho no Azure Cosmos DB.

1. Seleção da Chave de Partição Certa

Escolher uma chave de partição apropriada é vital para bancos de dados distribuídos como Cosmos DB. Uma boa chave de partição garante que os dados sejam distribuídos uniformemente entre as partições, reduzindo pontos de sobrecarga e melhorando o desempenho.

A seleção de uma chave de partição é simples, mas muito importante no momento do design no Azure Cosmos DB. Uma vez nós selecionamos a chave de partição, não é possível alterá-la no local.

Melhor Prática

  • Selecione uma chave de partição com alta cardinalidade (muitos valores únicos).
  • Garanta que distribua a leitura e gravação de forma equilibrada.
  • Mantenha dados relacionados juntos para minimizar consultas entre partições.

Exemplo: Criando um Contêiner com uma Chave de Partição Ótima

C#

 

var database = await cosmosClient.CreateDatabaseIfNotExistsAsync("YourDatabase");
var containerProperties = new ContainerProperties
{
    Id = "myContainer",
    PartitionKeyPath = "/customerId"  // Partition key selected to ensure balanced distribution
}; 

// Crie o contêiner com uma taxa de transferência provisionada de 400 RU/s
var container = await database.CreateContainerIfNotExistsAsync(containerProperties, throughput: 400);

2. Indexação Adequada Use Indexação

No Azure Cosmos DB, índices são aplicados a todas as propriedades por padrão, o que pode ser benéfico, mas pode resultar em custos aumentados de armazenamento e RU/s. Para melhorar o desempenho das consultas e minimizar despesas, considere personalizar a política de indexação. O Cosmos DB suporta três tipos de índices: Índices de Intervalo, Índices Espaciais e Índices Compostos. Use o tipo adequado com sabedoria.

Melhores Práticas

  • Exclua campos desnecessários da indexação.
  • Use índices compostos para consultas de múltiplos campos.

Exemplo: Política de Indexação Personalizada

C#

 

{
    "indexingPolicy": {
        "automatic": true,
        "indexingMode": "consistent",  // Can use 'none' or 'lazy' to reduce write costs
        "includedPaths": [
            {
                "path": "/orderDate/?",  // Only index specific fields like orderDate
                "indexes": [
                    {
                        "kind": "Range",
                        "dataType": "Number"
                    }
                ]
            }
        ],
        "excludedPaths": [
            {
                "path": "/largeDataField/*"  // Exclude large fields not used in queries
            }
        ]
    }
}

Exemplo: Adicionando um Índice Composto para Consultas Otimizadas

C#

 

{
    "indexingPolicy": {
        "compositeIndexes": [
            [
                { "path": "/lastName", "order": "ascending" },
                { "path": "/firstName", "order": "ascending" }
            ]
        ]
    }
}

Você pode ler mais sobre tipos de indexação aqui.

3. Otimize Consultas

A consulta eficiente é crucial para minimizar unidades de requisição (RU/s) e melhorar o desempenho no Azure Cosmos DB. O custo de RU/s depende da complexidade e do tamanho da consulta.

A utilização de executores em massa pode reduzir ainda mais os custos, diminuindo os RUs consumidos por operação. Essa otimização ajuda a gerenciar o uso de RU de forma eficaz e reduz suas despesas gerais com o Cosmos DB.

Melhores Práticas

  • Use consultas SELECT em quantidades limitadas, recupere apenas as propriedades necessárias.
  • Evite consultas entre partições fornecendo a chave de partição em sua consulta.
  • Use filtros em campos indexados para reduzir os custos de consulta.

Exemplo: Buscar Registro do Cliente

C#

 

var query = new QueryDefinition("SELECT c.firstName, c.lastName FROM Customers c WHERE c.customerId = @customerId")
    .WithParameter("@customerId", "12345");

var iterator = container.GetItemQueryIterator<Customer>(query, requestOptions: new QueryRequestOptions
{
    PartitionKey = new PartitionKey("12345")  // Provide partition key to avoid cross-partition query
});

while (iterator.HasMoreResults)
{
    var response = await iterator.ReadNextAsync();
    foreach (var customer in response)
    {
        Console.WriteLine($"{customer.firstName} {customer.lastName}");
    }
}

4. Ajuste dos Níveis de Consistência

Os níveis de consistência definem modos operacionais específicos projetados para atender garantias relacionadas à velocidade. Existem cinco níveis de consistência (Forte, Estabilidade Limitada, Sessão, Prefixo Consistente e Eventual) disponíveis no Cosmos DB. Cada nível de consistência impacta latência, disponibilidade e throughput.

Melhores Práticas

  • Use consistência de sessão para a maioria dos cenários para equilibrar desempenho e consistência de dados.
  • A consistência forte garante a consistência dos dados, mas aumenta o RU/s e a latência.

Exemplo: Definindo o Nível de Consistência

C#

 

var cosmosClient = new CosmosClient(
    "",
    "",
    new CosmosClientOptions
    {
        // Defina a consistência como "Sessão" para desempenho equilibrado
		ConsistencyLevel = ConsistencyLevel.Session      
});

Saiba mais sobre o nível de consistência aqui.

5.Use Provisioned Throughput (RU/s) and Auto-Scale Wisely

O provisionamento de throughput é um fator-chave para alcançar eficiência de custos e desempenho ótimo no Azure Cosmos DB. O serviço permite configurar o throughput de duas maneiras:

  • RU/s Fixo: Um nível constante e predefinido de Unidades de Requisição por segundo (RU/s), adequado para cargas de trabalho com demandas de desempenho consistentes.
  • Auto-Scale: Uma opção dinâmica que ajusta automaticamente o throughput com base em flutuações de carga de trabalho, fornecendo escalabilidade e evitando superprovisionamento durante períodos de baixa atividade.

Escolher o modelo de throughput apropriado ajuda a equilibrar as necessidades de desempenho com a gestão de custos de forma eficaz.

Melhores Práticas

  • Para cargas de trabalho previsíveis, provisione o throughput manualmente.
  • Use o auto-scale para cargas de trabalho imprevisíveis ou com picos de demanda.

Exemplo: Provisionamento de Throughput com Auto-Scale

C#

 

var throughputProperties = ThroughputProperties.CreateAutoscaleThroughput(maxThroughput: 4000);  // Autoscale up to 4000 RU/s 
var container = await database.CreateContainerIfNotExistsAsync(new ContainerProperties
{
	Id = "autoscaleContainer",
	PartitionKeyPath = "/userId"
}, throughputProperties);

Exemplo: Configurando Manualmente RU/s Fixo para Cargas de Trabalho Estáveis 

C#

 

var container = await database.CreateContainerIfNotExistsAsync(new ContainerProperties
{
    Id = "manualThroughputContainer",
    PartitionKeyPath = "/departmentId"
}, throughput: 1000);  // Fixed 1000 RU/s

6.Aproveite o Feed de Mudanças para Processamento Eficiente em Tempo Real

O feed de alterações permite o processamento em tempo real, baseado em eventos, capturando automaticamente as mudanças no banco de dados, eliminando a necessidade de pesquisa. Isso reduz a sobrecarga de consultas e aprimora a eficiência.

Melhores Práticas

  • Use o feed de alterações em cenários onde mudanças de dados em tempo real precisam ser processadas (por exemplo, análises em tempo real, notificações, alertas).

Exemplo: Lendo do Feed de Alterações

C#

 

var iterator = container.GetChangeFeedIterator(
ChangeFeedStartFrom.Beginning(),
ChangeFeedMode.Incremental);
while (iterator.HasMoreResults)
{
    var changes = await iterator.ReadNextAsync();
    foreach (var change in changes)
    {
        Console.WriteLine($"Detected change: {change.Id}");
        // Processar a alteração (por exemplo, acionar evento, atualizar cache)
    }
}

7. Utilização do Tempo de Vida (TTL) para Expiração Automática de Dados

Se você tem dados que são relevantes apenas por um tempo limitado, como logs ou dados de sessão, habilitar o Tempo de Vida (TTL) no Azure Cosmos DB pode ajudar a gerenciar os custos de armazenamento. O TTL deleta automaticamente os dados expirados após o período de retenção especificado, eliminando a necessidade de limpeza manual de dados. Essa abordagem não apenas reduz a quantidade de dados armazenados, mas também garante que seu banco de dados seja otimizado para eficiência de custos, removendo informações obsoletas ou desnecessárias.

Melhores Práticas

  • Defina o TTL para containers onde os dados devem expirar automaticamente para reduzir os custos de armazenamento.

Exemplo: Configurando o Tempo de Vida (TTL) para Dados Expirados

C#

 

{
    "id": "sessionDataContainer",
    "partitionKey": { "paths": ["/sessionId"] },
    "defaultTtl": 3600  // 1 hour (3600 seconds)
}

No Cosmos DB, o valor máximo de Tempo-para-Viver (TTL) que pode ser definido é de 365 dias (1 ano). Isto significa que os dados podem ser automaticamente excluídos após expirarem dentro de um ano da criação ou última modificação, dependendo de como você configura o TTL.

8. Avoid Cross-Partition Queries

Consultas entre partições podem aumentar significativamente os RU/s e a latência. Para evitar isso:

Melhores Práticas

  • Sempre inclua a chave de partição em suas consultas.
  • Projete sua estratégia de partição para minimizar o acesso entre partições.

Exemplo: Consultando com a Chave de Partição para Evitar Consultas entre Partições

C#

 

var query = new QueryDefinition("SELECT * FROM Orders o WHERE o.customerId = @customerId")
    .WithParameter("@customerId", "12345"); 

var resultSetIterator = container.GetItemQueryIterator<Order>(query, requestOptions: new QueryRequestOptions
{
    PartitionKey = new PartitionKey("12345")
});

while (resultSetIterator.HasMoreResults)
{
    var response = await resultSetIterator.ReadNextAsync();
    foreach (var order in response)
    {
        Console.WriteLine($"Order ID: {order.Id}");
    }
}

Conclusão

Estas dicas são muito eficazes durante o desenvolvimento. Ao implementar uma estratégia eficaz de partição, personalizando políticas de indexação, otimizando consultas, ajustando níveis de consistência e selecionando os modelos apropriados de provisionamento de throughput, você pode melhorar significativamente o desempenho e a eficiência da implantação do seu Azure Cosmos DB. Estas otimizações não apenas aprimoram a escalabilidade, mas também ajudam a gerenciar custos, proporcionando uma experiência de banco de dados de alto desempenho.

Source:
https://dzone.com/articles/optimizing-performance-in-azure-cosmos-db