I cinque livelli di consistenza

Azure Cosmos DB offre cinque livelli di consistenza che si dispongono su un continuum che bilancia tre grandezze in tensione tra loro: coerenza (freschezza e ordine delle letture), latenza e disponibilità/throughput. La regola mentale è: più forte è la garanzia, più alta è la latenza di scrittura in configurazioni multi-region e maggiore è il consumo di Request Unit (RU) per le letture. Il livello si imposta a livello di account, ma il client SDK può indebolirlo per singola richiesta (mai rafforzarlo oltre il default dell’account).

  • Strong: garantisce linearizzabilità: ogni lettura vede l’ultima scrittura committata. In un account multi-region obbliga il commit su un quorum globale, quindi introduce latenza e non è compatibile con più region di scrittura. Ideale per scenari di sola-lettura critica come inventari finanziari o leaderboard con valore univoco.
  • Bounded Staleness: le letture possono essere arretrate ma entro un limite definito da K versioni o da un intervallo di tempo T. Garantisce ordine globale (consistent prefix) fuori dalla finestra. Adatto quando serve quasi-freschezza con SLA di latenza migliori di Strong, tipicamente in scenari cross-region.
  • Session (default): garanzia per sessione legata a un session token. Lo stesso client legge le proprie scritture (read-your-writes), con monotonic reads/writes. Copre la stragrande maggioranza delle app web/mobile a costo e latenza contenuti.
  • Consistent Prefix: le letture non vedono mai scritture fuori ordine; possono essere arretrate ma l’ordine è preservato.
  • Eventual: nessuna garanzia d’ordine, massima disponibilità e latenza minima. Va bene per like, conteggi, telemetria dove la convergenza finale basta.

Un dettaglio d’esame: solo Strong e Bounded Staleness offrono garanzie legate agli SLA di consistenza e influenzano la scelta tra single/multi-region write.

Il change feed

Il change feed è un log persistente e ordinato delle modifiche (insert e update) applicate ai documenti di un container. Punti chiave:

  • L’ordine è garantito all’interno di ogni partizione logica (per partition key), non globalmente.
  • Registra la versione più recente di ogni documento nel modo latest version (default); non espone di per sé i delete — per intercettarli si usa il soft-delete con un flag TTL, oppure la modalità all versions and deletes dove disponibile.
  • È pull-based nella sua essenza, ma quasi sempre lo si consuma in modalità push tramite componenti gestiti.

Come consumarlo

  • Change Feed Processor (libreria .NET SDK): il pattern raccomandato per servizi long-running. Distribuisce le partizioni tra più istanze e mantiene il checkpoint dell’avanzamento in un lease container dedicato, garantendo bilanciamento e ripresa dopo un crash.
  • Azure Functions con Cosmos DB trigger: sotto il cofano usa lo stesso processor, ma serverless. È la scelta più rapida per architetture event-driven; richiede comunque un lease container.
var processor = container
    .GetChangeFeedProcessorBuilder<Doc>("materializer", HandleChangesAsync)
    .WithInstanceName("host-1")
    .WithLeaseContainer(leaseContainer)
    .Build();

Casi d’uso tipici: materialized view e denormalizzazioni pre-calcolate per query costose, replica verso un secondo container/servizio (es. sync su Azure AI Search o Data Lake), invalidazione cache, ed event sourcing che pubblica eventi su Event Hubs / Service Bus.

Trappole tipiche d’esame

  • Scenario: app globale multi-region che richiede “sempre l’ultimo dato” → la risposta d’istinto è Strong, ma se sono richieste multi-region write o bassa latenza globale, Strong è incompatibile/troppo costoso: preferire Bounded Staleness o Session. Strong non è quasi mai la scelta corretta in scenari multi-region.
  • Scenario: l’utente deve rileggere subito ciò che ha appena scritto sulla stessa web app → basta Session (default), non serve Strong; ricorda di propagare il session token tra le richieste dello stesso client.
  • Scenario: serve elaborare le modifiche in modo affidabile e scalabile con ripresa dopo failure → Change Feed Processor (o Functions trigger) con lease container per il checkpoint; non implementare polling manuale della query.
  • Scenario: serve intercettare le cancellazioni con il change feed → il modo latest version non le espone: usare soft-delete + TTL oppure la modalità all versions and deletes.
  • Scenario: costruire una vista aggregata o replicare dati verso un altro store → change feed verso materialized view, non trigger stored procedure sincroni che gravano sulle RU di scrittura.