GH GambleHub

CQRS e divisione lettura/scrittura

Cos'è il CQRS

CQRS (Command Query Responsibility Segregation) è un approccio architettonico che condivide il modello di dati e i componenti responsabili della scrittura (commands) e della lettura (queries).
L'idea è che il processo di modifica dello stato sia ottimizzato per gli invarianti validi e le transazioni, mentre la lettura per le proiezioni veloci, mirate e scalabili.

💡 I comandi modificano lo stato e restituiscono il risultato dell'operazione. Le richieste sono solo leggere e non hanno effetti collaterali.

Perché è necessario

Prestazioni di lettura: proiezioni materializzate in scenari specifici (nastri, report, directory).
La stabilità del percorso critico è isolata da joine e aggregazioni pesanti.
Libertà di selezione dello storage: OLTP per la scrittura, OLAP/cache/motori di ricerca per la lettura.
Evoluzione rapida: aggiungere nuove viste senza rischiare di rompere le transazioni.
Osservabilità e verifica (in particolare nel collegamento con Event Source): è più facile ripristinare e sovrascrivere lo stato.


Quando applicare (e quando no)

Adatto se:
  • Prevalgono le letture con tagli di dati diversi e aggregazioni complesse.
  • Il percorso di scrittura critico deve essere sottile e prevedibile.
  • Servono SLO/SLA diversi per la lettura e la scrittura.
  • È necessario isolare la logica di scrittura del dominio dalle esigenze analitiche/di ricerca.
Non va bene se:
  • Il dominio è semplice, il carico è basso; CRUD se la cava.
  • Una forte coerenza tra lettura e scrittura è obbligatoria per tutti gli script.
  • Il team è inesperto e la complessità operativa è inaccettabile.

Concetti di base

Comando (Command) - Intende modificare lo stato ('CreateOrder', 'CapturePayment'). Controlla gli invarianti.
Query - Recupero dei dati («GetOrderById», «ListUserTransactions»). Niente effetti collaterali.
Modello di scrittura: aggregazioni/invarianti/transazioni; memorizzazione - relazionale/chiave-valore/evento.
Modello di lettura (proiezioni) - Tabelle/indici/cash materializzate, sincronizzate in modo asincrono.
Coerenza: spesso eventual tra scrittura e lettura; percorsi critici attraverso la lettura diretta da un modello write.


Architettura (scheletro)

1. Servizio Write: accetta comandi, valuta invarianti, registra modifiche (database o eventi).
2. Outbox/CDC - Pubblicazione garantita del fatto di modifica.
3. Processori di proiezione: ascolti eventi/CDC e aggiorna i modelli read.
4. Servizio read: gestisce queries da viste/caselle/ricerche materializzate.
5. Sags/orchestrazione coordinano i processi di aggregazione crociata.
6. Osservabilità: layout di proiezioni, percentuale di applicazioni riuscite, DLQ.


Progettazione di un modello di scrittura

Aggregazioni: limiti di transazione chiari (ad esempio Order, Payment, UserBalance).
Invarianti: formalizza (≥ 0, unicità, limiti).
I comandi sono idipotenti (ad esempio, «idempotency _ key»).
Le transazioni sono minime per portata; effetti collaterali esterni tramite outbox.

Esempio di comando (pseudo-JSON)

json
{
"command": "CapturePayment",
"payment_id": "pay_123",
"amount": 1000,
"currency": "EUR",
"idempotency_key": "k-789",
"trace_id": "t-abc"
}

Progettazione del modello di lettura

Respingere le richieste: quali schermate/report sono necessari?
La denormalizzazione è valida: il modello read è una cache ottimizzata.
Più proiezioni per diverse attività: ricerca (OpenSearch), report (archivio colonne), schede (KV/Redis).
TTL e intersezione: le proiezioni devono essere in grado di ripristinare dall'origine (repliche di eventi/snapshot).


Coerenza e UX

Eventual consistency: l'interfaccia può mostrare i dati più recenti in breve tempo.
Pattern UX: «i dati vengono aggiornati»..., ottimistico UI, indicatori di sincronizzazione, blocco delle azioni pericolose prima della conferma.
Per le operazioni che richiedono una forte coerenza (ad esempio, la visualizzazione di un bilanciamento preciso prima del prelievo), leggere direttamente dal modello write.


CQRS e Event Source (opzionale)

Event Source (ES) memorizza gli eventi e lo stato dell'aggregazione è il risultato della loro coagulazione.
Il collegamento CQRS + ES fornisce un controllo perfetto e una facile intersezione delle proiezioni, ma aumenta la complessità.
Alternativa: normale OLTP-DATABASE + outbox/CDC di proiezione.


Replica Outbox e CDC

Outbox (in una singola transazione) - Scrittura delle modifiche di dominio + scrittura di un evento in outbox; Il Pabliser lo porta nello pneumatico.
CDC - La lettura da un database di database (Debezium, ecc.) → la trasformazione in eventi di dominio.
Garanzia: per impostazione predefinita, i consumatori e le proiezioni devono essere idipotenti.


Selezione dello storage

Write: relazionale (PostgreSQL/MySQL) per le transazioni; KV/Comment - dove gli invarianti sono semplici.

Read:
  • KV/Redis - schede e letture chiave veloci;
  • Ricerca (OpenSearch/Elasticsearch) - Ricerca/filtri/sfaccettature
  • Colonne (ClickHouse/BigQuery) - Report;
  • Kesh su CDN - cataloghi/contenuti pubblici.

Modelli di integrazione

livello API: endpoint/servizi separati per commands e queries.
Idampotenza: chiave dell'operazione nel titolo/corpo; storage recent-keys con TTL.
Sags/orchestrazione: timeout, compensi, ripetitività dei passi.
Backpressure limita il parallelismo dei processori di proiezione.


Osservabilità

Metriche write: p95/99 latitanza dei comandi, percentuale di transazioni riuscite, errori di convalida.
Metriche read: p95/99 query, hit-rate cache, carico del cluster di ricerca.
Combinazione di proiezioni (tempo e messaggi), puntata DLQ, percentuale di deduplicazione.
Tracing: «trace _ id» passa attraverso il comando outbox per la proiezione query.


Sicurezza e compilazione

Separazione dei diritti: scopes/ruoli diversi per la scrittura e la lettura il principio dei minori privilegi.
PII/PCI: minimizza le proiezioni; crittografia at-rest/in-flight occultamento.
Controllo: fissa il comando, l'attore, l'esito, 'trace _ id'; Archivi WORM per domini critici (pagamenti, KYC).


Test

Contract test: per i comandi (errori, invarianti) e queries (formati/filtri).
Progetti test - Invia una serie di eventi/CDC e controlla il modello read finale.
Chaos/latency: inserimento di ritardi nei processori di proiezione Verifica UX durante il raggio.
Replayability - Intersezione delle proiezioni sullo stand da snapshot/login.


Migrazione e evoluzione

I nuovi campi sono additivi nell'evento/CDC; i modelli read vengono riarrangiati.
Doppia voce (dual-write) per i diagrammi ridisegnati teniamo le vecchie proiezioni fino al cambio.
Versioning: «v1 »/« v2» eventi e endpoint, piano sunset.
Feature flags - Immettere nuove queries/proiezioni canarie.


Antipattern

CQRS «per la moda» in semplici servizi CRUD.
Severa dipendenza sincrona dalla lettura dalla scrittura (uccide l'isolamento e la resistenza).
Un indice per tutto: mescolare le richieste eterogenee in un read-store.
Nessuna idampotenza nelle proiezioni di doppie e discrepanze.
Proiezioni non riparabili (nessun replay/snapshot).


Esempi di domini

Pagamenti (servizio online)

Write: «Authorize», «Capture», «Refund» nel database transazionale; outbox pubblica'payment '.

Read:
  • Redis «carta di pagamento» per la UI;
  • ClickHouse per i report
  • OpenSearch per la ricerca delle transazioni.
  • Percorso critico: autorizzazione ≤ 800 ms p95 coerenza di lettura UI - avvenual (fino a 2-3 c).

KYC

Write: comandi di avvio/update dello stato; Deposito di PII in un database protetto.
Read: proiezione semplificata degli stati senza PII; Il PII viene tirato a punto se necessario.
Protezione: scopes diversi per la lettura dello stato e l'accesso ai documenti.

Bilanci (iGaming/Finanza)

Write: aggregato' UserBalance 'con aggregati/decrementi atomici; chiavi idonee per l'intervento.
Read: cache per «bilanciamento rapido» per il prelievo - lettura diretta da write (rigorosa coerenza).
I depositi e le conclusioni sono coordinati da eventi, in caso di guasti di risarcimento.


Assegno foglio di implementazione

  • Le unità e gli invarianti del modello write sono selezionati.
  • Definite le queries chiave e progettate le proiezioni sottostanti.
  • Sono stati configurati outbox/CDC e processori di proiezione idipotenti.
  • C'è un piano per l'intersezione delle proiezioni (snapshot/replay).
  • SLO: latitanza dei comandi, pianificazione delle proiezioni, disponibilità di read/write singolarmente.
  • I diritti di accesso e la crittografia dei dati sono stati condivisi.
  • Gli alert su DLQ/lega/errori di deduplicazione.
  • Test: contratti, proiezioni, caos, repliche.

FAQ

L'Event Source per CQRS è necessario?
No, no. Puoi costruire su un database normale + outbox/CDC.

Come si combatte la rassincronizzazione?
Progettare chiaramente UX, misurare la banda di proiezioni, permettere alle operazioni critiche di leggere da write.

È possibile mantenere sia write che read nello stesso servizio?
Sì, la separazione fisica è opzionale; la condivisione logica delle responsabilità è obbligatoria.

E le transazioni tra aggregazioni?
Attraverso le saghe e gli eventi; evitare transazioni distribuite, se possibile.


Totale

CQRS disattiva le mani con un percorso di scrittura sottile e affidabile con invarianti chiari e letture veloci e mirate da proiezioni materializzate. Migliora la produttività, semplifica l'evoluzione e rende il sistema più resistente ai carichi di lavoro - se gestito in modo disciplinato da coerenza, osservabilità e migrazioni.

Contact

Mettiti in contatto

Scrivici per qualsiasi domanda o richiesta di supporto.Siamo sempre pronti ad aiutarti!

Avvia integrazione

L’Email è obbligatoria. Telegram o WhatsApp — opzionali.

Il tuo nome opzionale
Email opzionale
Oggetto opzionale
Messaggio opzionale
Telegram opzionale
@
Se indichi Telegram — ti risponderemo anche lì, oltre che via Email.
WhatsApp opzionale
Formato: +prefisso internazionale e numero (ad es. +39XXXXXXXXX).

Cliccando sul pulsante, acconsenti al trattamento dei dati.