GH GambleHub

Read Models e proiezioni

Read Model è una tabella/indice/vista appositamente progettata per le letture veloci sotto uno specifico scenario alimentare. La proiezione è un processo che converte eventi/modifiche di origine in aggiornamenti di Read Model (solitamente idempotent upsert). In collegamento con CQRS, questo consente di scaricare il nucleo OLTP e stabilizzare p95/p99 letture, controllando la «freschezza».

Idee principali:
  • Denormalizzare come richiesta, non come «schema universale».
  • Aggiorna incrementalmente e idipotenzialmente.
  • Controlla chiaramente staleness e ordine.

1) Quando utilizzare Read Models (e quando no)

Adatto:
  • Frequenti letture pesanti (joine/aggregazioni/ordinamento) con ritardi di aggiornamento consentiti.
  • Dashboard, cataloghi, landing, top-N, fidi personali, liste di ricerca.
  • Separazione del carico: il kernel write è rigoroso, il piano read è veloce e scalabile.
Non è adatto:
  • Operazioni che richiedono rigorosi invarianti per ogni registrazione (denaro, unicità). C'è strong path.

2) Tracciato architettonico (schema verbale)

1. Origine delle modifiche: eventi di dominio (event source) o CDC da OLTP.
2. Trasportatore di proiezioni: parser, aggregazione/denormalizzazione dell'idempotent upsert.
3. Read Store: database/indice ottimizzato per richiesta (RDBMS, invertebrati, ricerca).
4. API/client: SELECT/GET veloce, con attributi «as _ of/freshness».

3) Progettazione di Read Model

Per iniziare, quali campi, filtri, ordinamenti, paginazioni, top-N?
Denormalizza: memorizza i dati già combinati (nomi, importi, stati).

Chiavi:
  • Partizionamento per «tenant _ id», data, regione.
  • Primary key: chiave aziendale + bidone temporale (ad esempio, '(tenant _ id, entity _ id)' o '(tenant _ id, bucket _ minute)').
  • Indici per where/order by frequente.
  • TTL/retenschn per vetrine temporanee (ad esempio 90 giorni).

4) Flusso di aggiornamenti e idepotenza

Idempotent upsert è la base della stabilità delle proiezioni.

Pseudo:
sql
-- Projection table
CREATE TABLE read_orders (
tenant_id  TEXT,
order_id  UUID,
status   TEXT,
total    NUMERIC(12,2),
customer  JSONB,
updated_at TIMESTAMP,
PRIMARY KEY (tenant_id, order_id)
);

-- Idempotent update by event
INSERT INTO read_orders(tenant_id, order_id, status, total, customer, updated_at)
VALUES (:tenant,:id,:status,:total,:customer,:ts)
ON CONFLICT (tenant_id, order_id) DO UPDATE
SET status = EXCLUDED. status,
total = EXCLUDED. total,
customer = COALESCE(EXCLUDED. customer, read_orders. customer),
updated_at = GREATEST(EXCLUDED. updated_at, read_orders. updated_at);
Regole:
  • Ogni messaggio porta una versione/ora; accettiamo solo «fresco o uguale» (idempotency).
  • Per le unità (contatori, importi) - Memorizzare lo state e utilizzare gli aggiornamenti switch (o gli approcci CRDT).

5) Origine modifiche: eventi vs CDC

Eventi (event surcing) - Ricca semantica, facile da costruire proiezioni diverse; l'evoluzione dei circuiti è importante.
CDC (replica logica): facile da collegare al database esistente Ci vorrà un mupping e un filtraggio degli update acustici.

Entrambe le opzioni richiedono:
  • Garanzie di consegna (at-least-once) e DLQ per i messaggi «velenosi».
  • Ordine chiave (partition key = 'tenant _ id: entity _ id').

6) Ordine, causalità e «freschezza»

Ordine chiave: gli eventi di un singolo oggetto devono venire in sequenza. Utilizzare la partizionalizzazione e le versioni.
Causalità (sessions/causal) - In modo che l'autore veda le sue modifiche (RYW), trasmettere la versione watermark nelle query.
Freschezza (bounded staleness) - Restituisci «as _ of »/« X-Data-Freshness» e tieni SLO (ad esempio p95-60 c).

7) Unità incrementali e top-N

Esempio di bustini di vendita minuti:
sql
CREATE TABLE read_sales_minute (
tenant_id TEXT,
bucket  TIMESTAMP, -- toStartOfMinute revenue  NUMERIC(14,2),
orders  INT,
PRIMARY KEY (tenant_id, bucket)
);

-- Update by Event
INSERT INTO read_sales_minute(tenant_id, bucket, revenue, orders)
VALUES (:tenant,:bucket,:amount, 1)
ON CONFLICT (tenant_id, bucket) DO UPDATE
SET revenue = read_sales_minute. revenue + EXCLUDED. revenue,
orders = read_sales_minute. orders + 1;
Per top-N:
  • Supporta la vetrina classificata (ad esempio, «revenue DESC») e aggiorna solo le posizioni modificate (heap/skiplist/limited table).
  • Salvare la finestra del top (ad esempio 100-1000 righe per segmento).

8) Ricerca e geo-proiezione

Cerca (ES/Opensearch) - Documento denormalizzato, trasformazioni pipeline, versione del documento = versione sorgente.
Geo: memorizzà POINT/LAT, LON ", precompilate i tyli/quadrotri.

9) Multi-tenente e regioni

«tenant _ id» è obbligatorio nelle chiavi di proiezione ed eventi.
Fairness: limitare il throughput delle proiezioni per tenant (WFQ/DRR) in modo che il rumore non freni gli altri.
Residency: la proiezione vive nella stessa regione del nucleo write; vetrine interregionali - aggregazioni/resoconti.

10) Osservabilità e SLO

Metriche:
  • «progection _ lag _ ms» (istochnik→vitrina), «freshness _ age _ ms» (dall'ultimo delta).
  • throughput update, quota di errori, DLQ-rate, redrive-success.
  • Dimensioni delle vetrine, p95/p99 latitanza delle letture.
Tracing/logi:
  • Теги: `tenant_id`, `entity_id`, `event_id`, `version`, `projection_name`, `attempt`.
  • Annotazioni: soluzioni merge, passaggi di versione obsoleti.

11) Playbooks (runbooks)

1. Crescita del raggio: controllare il connettore/broker, aumentare le partenze, includere la priorità delle vetrine chiave.
2. Molti errori di schema: congelare i redrave, migrare gli schemi (backfill), riavviare con la nuova versione del mapper.
3. DLQ ripetuti: ridurre il batch, attivare il processore shadow e aumentare l'idampotenza.
4. Incoerenza della vetrina: esegue rebuild da registro/sorgente per finestra (selettivo per tenant/partition).
5. Chiavi hot: limitare la concorrenza della chiave, aggiungere code locali, portare l'aggregazione in una vetrina separata.

12) Conteggio completo (rebuild) e backfill

Approccio:
  • Interrompe il consumo (o passa alla nuova versione della vetrina).
  • Conteggia i pacchetti (per partizioni/date/tenanti).
  • Attiva il maglione a due fasi: prima riempiamo "read" v2 ", poi alterniamo atomicamente il routing di lettura.

13) Evoluzione dei circuiti (versioning)

'schema _ version'negli eventi/documenti.
La proiezione può leggere più versioni, la migrazione al volo.
Per i grandi cambiamenti, la nuova vetrina v2 e il traffico canareo.

14) Sicurezza e accesso

Ereditare RLS/ACL dall'origine; non fare in modo che la vetrina sia più ampia rispetto ai dati originali.
Mascherare il PII in proiezioni non necessarie per UX/analisi.
Controllo delle redrivisitazioni/rivisitazioni/modifiche manuali.

15) Modello di configurazione

yaml projections:
read_orders:
source: kafka. orders. events partition_key: "{tenant_id}:{order_id}"
idempotency: version_ts upsert:
table: read_orders conflict_keys: [tenant_id, order_id]
freshness_slo_ms: 60000 dlq:
topic: orders. events. dlq redrive:
batch: 500 rate_limit_per_sec: 50 read_sales_minute:
source: cdc. orders partition_key: "{tenant_id}:{bucket_minute}"
aggregate: increment retention_days: 90 limits:
per_tenant_parallelism: 4 per_key_serial: true observability:
metrics: [projection_lag_ms, dlq_rate, redrive_success, read_p95_ms]

16) Errori tipici

«Una vetrina per tutti i casi».
La mancanza di idampotenza delle riprese/corse negli apparecchi.
Dual-write direttamente in vetrina e OLTP → la soluzione temporanea.
Zero visibilità di freschezza, conflitto di aspettative con il prodotto.
Rebuild, senza un maglioncino a due →, è un buco nelle risposte.
Niente partitura/indici, aumento dei costi e della latitanza.

17) Ricette veloci

Catalogo/ricerca: vetrina documentale + upsert incrementale, lag 5-15 c, indici sotto i filtri.
I Dashboard sono botti minuti/orologio, unità SUM/COUNT, p95 freschezza 60 c.
Nastro personale: proiezione utente + causal/RYW per l'autore, fallback per la cache.
SaaS globale: vetrine regionali, unità cross-regionali; fairness per tenant.

18) Foglio di assegno prima della vendita

  • La vetrina è progettata per una richiesta specifica; ci sono indici e partenze.
  • L'origine delle modifiche è selezionata (eventi/CDC); garanzia di spedizione e ordine su chiave.
  • upsert idempotente con versioni/tempo; Protezione contro i vecchi eventi.
  • Il SLO di freschezza è definito e dato nelle risposte ('as _ of/freshness').
  • Il DLQ e il redrave sicuro sono configurati; playbook su rebuild/backfill.
  • Limitazioni della concorrenza (per-key serial) e fairness per tenant.
  • Metriche di laga/errori/latency, alert per p95/p99 e crescita del DLQ.
  • Versioning degli schemi e strategia delle migrazioni (v2 + maglioni).
  • I criteri di accesso/PII sono stati ereditati e convalidati.

Conclusione

Il Read Models e le proiezioni sono un acceleratore di lettura ingegneristico, che offre un piccolo prezzo per la freschezza e l'infrastruttura di streaming per ottenere millisecondi prevedibili e scaricare il kernel. Progettate le vetrine sotto richiesta, rendete idompotenti gli update, misurate la lega e promettete chiaramente freschezza, e le vostre API rimarranno veloci anche se aumentano il carico di lavoro, i dati e la geografia.

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.