Optimisation des performances dans Azure Cosmos DB : meilleures pratiques et astuces

Lorsque nous travaillons avec une base de données, l’optimisation est cruciale et clé en termes de performance et d’efficacité de l’application. De même, dans Azure Cosmos DB, l’optimisation est cruciale pour maximiser l’efficacité, minimiser les coûts et garantir que votre application évolue de manière efficace. Voici quelques-unes des meilleures pratiques avec des exemples de code pour optimiser les performances dans Azure Cosmos DB.

1. Sélection de la bonne clé de partition

Choisir une clé de partition appropriée est essentiel pour les bases de données distribuées comme Cosmos DB. Une bonne clé de partition garantit une distribution équilibrée des données entre les partitions, réduisant les points chauds et améliorant les performances.

La sélection d’une clé de partition est simple mais très importante lors de la conception dans Azure Cosmos DB. Une fois nous avons sélectionné la clé de partition, il n’est pas possible de la modifier sur place.

Meilleure pratique

  • Sélectionnez une clé de partition avec une haute cardinalité (beaucoup de valeurs uniques).
  • Assurez-vous qu’elle distribue les lectures et écritures de manière équilibrée.
  • Gardez les données connexes ensemble pour minimiser les requêtes entre partitions.

Exemple: Créer un conteneur avec une clé de partition optimale

C#

 

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

// Créez le conteneur avec un débit provisionné de 400 RU/s
var container = await database.CreateContainerIfNotExistsAsync(containerProperties, throughput: 400);

2. Adaptation appropriée Utilisation de l’indexation

Dans Azure Cosmos DB, les index sont appliqués par défaut à toutes les propriétés, ce qui peut être bénéfique mais peut entraîner des coûts de stockage et de RU/s plus élevés. Pour améliorer les performances des requêtes et minimiser les dépenses, envisagez de personnaliser la stratégie d’indexation. Cosmos DB prend en charge trois types d’index : les index de plage, les index spatiaux et les index composites. Utilisez judicieusement le bon type.

Bonne pratique

  • Exclure les champs inutiles de l’indexation.
  • Utilisez des index composites pour les requêtes multi-champs.

Exemple : Politique d’indexation personnalisée

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
            }
        ]
    }
}

Exemple : Ajout d’un index composite pour une requête optimisée

C#

 

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

Vous pouvez en savoir plus sur les types d’indexation ici.

3. Optimiser les requêtes

Une requête efficace est cruciale pour minimiser les unités de demande (RU/s) et améliorer les performances dans Azure Cosmos DB. Le coût en RU/s dépend de la complexité et de la taille de la requête.

L’utilisation des exécuteurs en masse peut réduire davantage les coûts en diminuant les RUs consommés par opération. Cette optimisation aide à gérer efficacement l’utilisation des RUs et à réduire vos dépenses globales sur Cosmos DB.

Meilleure pratique

  • Utilisez des requêtes SELECT en quantité limitée, ne récupérez que les propriétés nécessaires.
  • Évitez les requêtes inter-partitions en fournissant la clé de partition dans votre requête.
  • Utilisez des filtres sur les champs indexés pour réduire les coûts des requêtes.

Exemple : Récupérer l’enregistrement du client

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. Optimisation des niveaux de cohérence

Les niveaux de cohérence définissent des modes opérationnels spécifiques conçus pour garantir des performances. Il existe cinq niveaux de cohérence (Fort, Bornée, Session, Préfixe Cohérent et Évolutif) disponibles dans Cosmos DB. Chaque niveau de cohérence impacte la latence, la disponibilité et le débit.

Meilleure pratique

  • Utilisez la cohérence de session pour la plupart des scénarios afin de trouver un équilibre entre les performances et la cohérence des données.
  • Cohérence forte garantit la cohérence des données mais augmente les RU/s et la latence.

Exemple : Définir le niveau de cohérence

C#

 

var cosmosClient = new CosmosClient(
    "",
    "",
    new CosmosClientOptions
    {
        // Définir la cohérence sur "Session" pour des performances équilibrées
		ConsistencyLevel = ConsistencyLevel.Session      
});

En savoir plus sur le niveau de cohérence ici.

5. Utilisez les débits provisionnés (RU/s) et l’auto-évolutivité de manière avisée

La provision de débit est un facteur clé pour atteindre à la fois une efficacité de coût et des performances optimales dans Azure Cosmos DB. Le service vous permet de configurer le débit de deux manières :

  • RU/s fixe: Un niveau prédéfini et constant d’unités de requête par seconde (RU/s), adapté aux charges de travail avec des demandes de performances constantes.
  • Auto-évolutivité: Une option dynamique qui ajuste automatiquement le débit en fonction des fluctuations de la charge de travail, offrant une évolutivité tout en évitant la surprovisionnement pendant les périodes d’activité faible.

Le choix du modèle de débit approprié permet de concilier efficacement les besoins de performance avec la gestion des coûts.

Meilleure pratique

  • Pour des charges de travail prévisibles, provisionnez le débit manuellement.
  • Utilisez l’auto-évolutivité pour des charges de travail imprévisibles ou à pics.

Exemple : Provisionnement de débit avec Auto-évolutivité

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

Exemple : Définition manuelle des RU/s fixes pour des charges de travail stables 

C#

 

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

6. Tirez parti de Change Feed pour un traitement en temps réel efficace

Le flux de changement permet un traitement en temps réel basé sur les événements en capturant automatiquement les changements dans la base de données, éliminant ainsi le besoin de sondages. Cela réduit les frais de requête et améliore l’efficacité.

Meilleure pratique

  • Utilisez le flux de changement pour les scénarios où les changements de données en temps réel doivent être traités (par exemple, l’analyse en temps réel, les notifications, les alertes).

Exemple : Lecture du flux de changement

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}");
        // Traiter le changement (par exemple, déclencher un événement, mettre à jour le cache)
    }
}

7. Utilisation de l’expiration des données automatique avec le Time-to-Live (TTL)

Si vous avez des données qui ne sont pertinentes que pendant un temps limité, telles que des journaux ou des données de session, activer le Time-to-Live (TTL) dans Azure Cosmos DB peut aider à gérer les coûts de stockage. Le TTL supprime automatiquement les données expirées après la période de rétention spécifiée, éliminant ainsi le besoin de nettoyage manuel des données. Cette approche permet non seulement de réduire la quantité de données stockées, mais garantit également que votre base de données est optimisée en termes de rentabilité en supprimant les informations obsolètes ou inutiles.

Meilleure pratique

  • Définissez le TTL pour les conteneurs où les données doivent expirer automatiquement afin de réduire les coûts de stockage.

Exemple : Configuration du Time-to-Live (TTL) pour l’expiration des données

C#

 

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

Dans Cosmos DB, la valeur maximale de Temps de Vie (TTL) qui peut être définie est de 365 jours (1 an). Cela signifie que les données peuvent être automatiquement supprimées après leur expiration dans l’année suivant leur création ou leur dernière modification, selon la façon dont vous configurez le TTL.

8. Évitez les Requêtes Inter-Partitions

Les requêtes inter-partitions peuvent augmenter considérablement le RU/s et la latence. Pour éviter cela :

Meilleure Pratique

  • Incluez toujours la clé de partition dans vos requêtes.
  • Concevez votre stratégie de partitionnement pour minimiser l’accès inter-partitions.

Exemple : Effectuer une Requête Avec la Clé de Partition pour Éviter une Requête Inter-Partitions

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}");
    }
}

Conclusion

Ces conseils sont très efficaces lors du développement. En mettant en œuvre une stratégie de partitionnement efficace, en personnalisant les politiques d’indexation, en optimisant les requêtes, en ajustant les niveaux de cohérence et en sélectionnant les modèles de provisionnement de débit appropriés, vous pouvez grandement améliorer les performances et l’efficacité de votre déploiement Azure Cosmos DB. Ces optimisations non seulement améliorent la scalabilité mais aident également à gérer les coûts tout en offrant une expérience de base de données haute performance.

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