Introduction
Azure Cosmos DB est la base de données NoSQL multi-modèle de Microsoft Azure, offrant une scalabilité horizontale illimitée, une distribution globale et des SLAs de 99,999 % de disponibilité. En 2026, avec l'essor des applications IA et serverless, maîtriser Cosmos DB est essentiel pour gérer des charges massives sans downtime. Ce tutoriel avancé vous guide pas à pas pour créer un compte, partitionner des conteneurs, optimiser les RU/s (Request Units), implémenter des queries SQL complexes et configurer des politiques d'indexation avancées via le SDK TypeScript.
Pourquoi c'est crucial ? Une mauvaise partition amène des hotspots et des coûts explosifs ; une indexation sur-optimisée consomme des RU inutiles. Nous illustrons chaque concept avec du code fonctionnel, copier-collable, et des analogies comme un 'répartiteur de charge intelligent' pour le partitioning. À la fin, vous scalerez des millions d'opérations/seconde. Prêt à transformer votre backend en machine scalable ? (128 mots)
Prérequis
- Compte Azure actif avec abonnement payant (free tier limité pour scaling).
- Node.js 20+ et npm/yarn installés.
- Azure CLI installée et authentifiée (
az login). - Connaissances avancées en TypeScript, async/await et bases NoSQL.
- Clé d'API Cosmos DB (Endpoint + Primary Key) de votre compte.
- VS Code avec extension Azure Cosmos DB pour debugging.
Installation du SDK Cosmos DB
npm init -y
npm install @azure/cosmos @azure/identity dotenv
npm install -D @types/node typescript ts-node
mkdir cosmos-scaling-demo
cd cosmos-scaling-demo
tsc --init --target es2022 --module commonjs --outDir ./dist --rootDir ./src
echo 'COSMOS_ENDPOINT=your-endpoint.azure.com:443/
COSMOS_KEY=your-primary-key==
DATABASE_ID=ScalingDB' > .envCe script initialise un projet Node.js avec le SDK officiel @azure/cosmos pour interagir programmatiquement avec Cosmos DB. L'extension @azure/identity gère l'authentification AAD pour la prod ; dotenv charge les secrets. Évitez les clés hardcodées : utilisez Azure Key Vault en prod pour la rotation automatique.
Comprendre la connexion et les bases
La connexion à Cosmos DB utilise un endpoint HTTPS sécurisé et une clé primaire (ou AAD). Pensez-y comme à une 'porte d'entrée globale' : toutes les ops passent par elle, mais le scaling est géré en backend. Avant de scaler, provisionnez un compte avec API SQL (multi-modèle : documents, graph, etc.). Via Portal Azure, activez Analytical Store pour Synapse Link et Serverless pour burst traffic. Vérifiez les RU/s : 400 min par conteneur, scalables à des millions.
Créer la base de données et conteneur partitionné
import { CosmosClient } from '@azure/cosmos';
import dotenv from 'dotenv';
dotenv.config();
const client = new CosmosClient({ endpoint: process.env.COSMOS_ENDPOINT!, key: process.env.COSMOS_KEY! });
const databaseId = process.env.DATABASE_ID!;
async function main() {
const { database } = await client.databases.createIfNotExists({ id: databaseId });
console.log(`DB créée: ${databaseId}`);
const containerId = 'Users';
const partitionKey = { paths: ['/userId'], version: 2 };
await database.containers.createIfNotExists({
id: containerId,
partitionKey,
indexingPolicy: {
indexingMode: 'consistent',
includedPaths: [{ path: '/*' }],
excludedPaths: [{ path: '/_etag/?' }]
},
defaultTtl: 3600
});
console.log(`Conteneur partitionné créé: ${containerId}`);
}
main().catch(console.error);Ce code crée une DB et un conteneur avec partition key /userId (v2 pour hashing logique), indexation consistante et TTL de 1h. La partition évite les hotspots : imaginez des 'silos' par userId pour scaling horizontal. Piège : sans partition, limite 10GB/conteneur ; toujours tester avec charges synthétiques.
Maîtriser le partitioning avancé
Partitioning logique : Choisissez une clé à haute cardinalité (ex: userId, timestamp) pour distribuer uniformément. Cosmos DB auto-repartit les partitions physiques (150GB max chacune). Pour cross-partition queries, limitez avec EnableCrossPartitionQuery: false si possible. Analogy : comme un restaurant avec tables par groupe – trop de clients par table = bottleneck.
Insérer des données massives et query pointue
import { CosmosClient } from '@azure/cosmos';
import dotenv from 'dotenv';
dotenv.config();
const client = new CosmosClient({ endpoint: process.env.COSMOS_ENDPOINT!, key: process.env.COSMOS_KEY! });
const database = client.database(process.env.DATABASE_ID!);
const container = database.container('Users');
async function main() {
// Bulk insert (100 items)
const items = [];
for (let i = 0; i < 100; i++) {
items.push({
id: `user${i}`,
userId: `userPartition${Math.floor(i / 10)}`,
name: `User ${i}`,
score: Math.random() * 100,
tags: ['premium', 'active'],
timestamp: new Date().toISOString()
});
}
const { result: inserted } = await container.items.createMany(items);
console.log(`${inserted.length} items insérés`);
// Point query (intra-partition)
const { resources: user } = await container.item('user0', 'userPartition0').read();
console.log('User retrouvé:', user);
}
main().catch(console.error);Utilisez createMany pour bulk ops (jusqu'à 500 items/req, 5MB max) afin de minimiser les RU/s. Query pointue avec id + partitionKey est la plus efficace (1 RU). Évitez les scans : toujours spécifiez partitionKey pour <10 RU vs 1000+ en cross-partition.
Query SQL avancée avec agrégats
SELECT c.userId, AVG(c.score) AS avgScore, COUNT(c.id) AS userCount
FROM c
WHERE c.tags @> ['premium'] AND c.timestamp > '2026-01-01T00:00:00Z'
GROUP BY c.userId
ORDER BY avgScore DESC
OFFSET 0 LIMIT 10Cette query SQL utilise JSON operators (@>), filtre temporel, GROUP BY et pagination (OFFSET/LIMIT). Efficace avec index sur /tags et /timestamp. Coût : ~50 RU pour 1k items ; testez dans Data Explorer pour profiler.
Queries et optimisation RU/s
Exécutez la query via SDK avec container.items.query(querySpec). Profilez les RU dans le portail (Metrics tab). Astuces : ORDER BY sur partition key, éviter SELECT * (utilisez VALUE ou projection). Pour analytical, activez Spark Connector.
Exécuter la query SQL dans TypeScript
import { CosmosClient, SqlQuerySpec } from '@azure/cosmos';
import dotenv from 'dotenv';
dotenv.config();
const client = new CosmosClient({ endpoint: process.env.COSMOS_ENDPOINT!, key: process.env.COSMOS_KEY! });
const container = client.database(process.env.DATABASE_ID!).container('Users');
const querySpec: SqlQuerySpec = {
query: "SELECT c.userId, AVG(c.score) AS avgScore FROM c WHERE c.tags @> ['premium'] GROUP BY c.userId"
};
async function main() {
const { resources, requestCharge } = await container.items.query(querySpec).fetchAll();
console.log(`Résultats:`, resources);
console.log(`RU consommés: ${requestCharge}`);
}
main().catch(console.error);fetchAll() pour petits résultats ; utilisez itérateurs pour >100k. Loggez requestCharge pour tuning. Piège : cross-partition GROUP BY peut exploser les RU – partitionnez par userId pour intra-partition.
Politique d'indexation custom (JSON)
{
"indexingMode": "consistent",
"automatic": true,
"includedPaths": [
{ "path": "/userId/?", "indexes": [{ "kind": "Hash", "dataType": "String", "precision": -1 }] },
{ "path": "/score/?", "indexes": [{ "kind": "Number", "dataType": "Number", "precision": -1 }] },
{ "path": "/tags/?" }
],
"excludedPaths": [
{ "path": "/timestamp/?" },
{ "path": "/*" }
],
"spatialIndexes": [],
"compositeIndexes": [
[
{ "path": "/userId", "order": "ascending" },
{ "path": "/score", "order": "descending" }
]
]
}Cette policy indexe sélectivement (Hash pour strings, Number pour score) et exclut timestamp pour économies RU (10-20%). Composite pour ORDER BY userId+score. Appliquez-la lors du createIfNotExists ; rebuild coûteux sur gros conteneurs.
Change Feed pour scaling événementiel
import { CosmosClient, ChangeFeedIterator } from '@azure/cosmos';
import dotenv from 'dotenv';
dotenv.config();
const client = new CosmosClient({ endpoint: process.env.COSMOS_ENDPOINT!, key: process.env.COSMOS_KEY! });
const container = client.database(process.env.DATABASE_ID!).container('Users');
async function main() {
const iterator: ChangeFeedIterator<any> = container.items.readChangeFeed({
startFromBeginning: false
});
let count = 0;
while (!(await iterator.hasMoreResults())) {
const response = await iterator.fetchNext();
count += response.resources.length;
console.log(`Changements lus: ${count}`);
// Traitez pour Azure Functions/Event Hubs
}
}
main().catch(console.error);Change Feed capture les upserts/deletes en ordre par partition, parfait pour CDC (Change Data Capture) vers Kafka ou Functions. Scaling : parallèle par partition. Limite : lease container requis pour multi-instances.
Bonnes pratiques
- Choisissez RU autoscale (10x-100x max) pour workloads variables ; monitor via Metrics API.
- Implémentez fan-out : queries par partition en parallèle avec Promise.all.
- Utilisez Serverless v2 pour <5% utilisation ; migrez vers provisioned pour prédictible.
- Activez multi-region writes pour latence <10ms globale.
- Profilez toujours : ciblez <5 RU/query avec indexing policy minimaliste.
Erreurs courantes à éviter
- Hot partitions : clé à faible cardinalité (ex: /country) → uniformisez avec composite (userId + region).
- Cross-partition queries excessives : coût x10 ; refactorisez en app-level aggregation.
- Indexation full : double les RU d'insert ; excluez champs non-queriés.
- TTL sur partition key : peut causer rebalancing coûteux ; testez avec Autopilot.
Pour aller plus loin
- Docs officielles : Azure Cosmos DB SDK
- Outils : Cosmos DB Emulator pour dev local.
- Scaling extrême : intégrez avec Azure Functions Cosmos trigger.
- Découvrez nos formations Learni sur Azure pour certifs DP-420.