GH GambleHub

Read Models und Projektionen

Read Model ist eine speziell entworfene Tabelle/Index/Ansicht für schnelle Lesungen für ein bestimmtes Produktszenario. Projektion - Ein Prozess, der Ereignisse/Quelländerungen in Read Model-Updates umwandelt (normalerweise idempotent upsert). In Verbindung mit CQRS ermöglicht dies die Entlastung des OLTP-Kernels und die Stabilisierung der p95/p99-Lesungen durch Steuerung der „Frische“.

Die wichtigsten Ideen:
  • Denormalisierung auf Anfrage, nicht „universelles Schema“.
  • Inkrementell und idempotent aktualisieren.
  • Eindeutig verwalten staleness und Ordnung.

1) Wann man Read Models verwendet (und wann nicht)

Geeignet für:
  • Häufiges schweres Lesen (Joins/Aggregation/Sortierung) mit zulässiger Aktualisierungsverzögerung.
  • Dashboards, Kataloge, Landings, „Top N“, persönliche Feeds, Suchlisten.
  • Lastverteilung: Write-Core ist streng, Read-Plane ist schnell und skalierbar.
Nicht geeignet:
  • Operationen, die strenge Invarianten „für jeden Datensatz“ erfordern (Geld, Einzigartigkeit). Da ist ein starker Pfad.

2) Architektonische Kontur (verbales Schema)

1. Quelle der Änderungen: Domain Events (Event Sourcing) oder CDC aus OLTP.
2. Projektionspipeline: Parser → Aggregation/Denormalisierung → idempotent upsert.
3. Read Store: DB/Index optimiert für Anfrage (RDBMS, Säulen-, Suchmaschinen).
4. API/Client: schnelles SELECT/GET mit den Attributen „as_of/freshness“.

3) Design des Lesemodells

Beginnen Sie mit der Abfrage: welche Felder, Filter, Sortierung, Pagination, Top N?
Denormalisieren: Speichern Sie bereits zusammengeführte Daten (Namen, Beträge, Status).

Schlüssel:
  • Partitionierung: nach 'tenant _ id', Datum, Region.
  • Primärschlüssel: Geschäftsschlüssel + temporäres Baquet (z. B.'(tenant_id, entity_id) 'oder' (tenant_id, bucket_minute)').
  • Indizes: durch häufige where/order by.
  • TTL/retention: für temporäre Vitrinen (z.B. 90 Tage).

4) Aktualisierungsfluss und Idempotenz

Idempotent upsert ist die Basis für die Stabilität von Projektionen.

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);
Regeln:
  • Jede Nachricht trägt eine Version/Zeit; Wir akzeptieren nur „frisch oder gleich“ (idempotency).
  • Für Aggregate (Zähler, Summen) - State speichern und kommutative Updates (oder CRDT-Ansätze) verwenden.

5) Quelle der Veränderung: Ereignisse vs CDC

Veranstaltungen (Event Sourcing): reiche Semantik, einfach, verschiedene Projektionen zu bauen; Die Entwicklung von Schemata ist wichtig.
CDC (logische Replikation): einfach an eine bestehende Datenbank anschließen; Mupping- DML→sobyty und Filterung von Rausch-Updates sind erforderlich.

Beide Optionen erfordern:
  • Versandgarantien (at-least-once) und DLQ für „giftige“ Nachrichten.
  • Reihenfolge nach Schlüssel (partition key = 'tenant _ id: entity _ id').

6) Ordnung, Kausalität und „Frische“

Die Reihenfolge nach dem Schlüssel: die Ereignisse eines Objektes sollen nacheinander kommen; Partitionierung und Versionen verwenden.
Kausalität (Sitzung/causal): Damit der Autor seine Änderungen (RYW) sieht, übergeben Sie die Wasserzeichen-Version in Abfragen.
Frische (bounded staleness): Geben Sie „as _ of “/„ X-Data-Freshness“ zurück und halten Sie den SLO (z. B. p95 ≤ 60 c).

7) Inkrementelle Aggregate und Top N

Beispiel für Minutenverkaufsbakets:
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;
Für die Top N:
  • Pflegen Sie ein Ranking-Showcase (z.B. nach 'revenue DESC') und aktualisieren Sie nur die geänderten Positionen (heap/skiplist/limited table).
  • Speichern Sie das „Fenster“ der Spitze (z. B. 100-1000 Zeilen pro Segment).

8) Such- und Geo-Projektionen

Suche (ES/Opensearch): denormalisiertes Dokument, Pipeline von Transformationen, Dokumentversion = Quellversion.
Geo: Speichern Sie' POINT/LAT, LON', vorher aggregieren Sie die Tiers/Quadrotry.

9) Multi-Tenant und Regionen

'tenant _ id' ist in Projektionsschlüsseln und Ereignissen obligatorisch.
Fairness: Begrenzen Sie throughput Projektionen per tenant (WFQ/DRR), damit „noise“ die anderen nicht bremst.
Residency: Die Projektion lebt in der gleichen Region wie der Write-Core; interregionale Vitrinen - Aggregate/Zusammenfassungen.

10) Beobachtbarkeit und SLO

Metriken:
  • 'projection _ lag _ ms' (istochnik→vitrina), 'freshness _ age _ ms' (seit dem letzten Delta).
  • throughput-Aktualisierungen, Fehlerquote, DLQ-Rate, Redrive-Erfolg.
  • Größe der Vitrinen, p95/p99 Latenz der Lesungen.
Tracing/Logs:
  • Теги: `tenant_id`, `entity_id`, `event_id`, `version`, `projection_name`, `attempt`.
  • Anmerkungen: Merge-Lösungen, Auslassungen veralteter Versionen.

11) Playbooks (Runbooks)

1. Lagwachstum: Überprüfen Sie den Konnektor/Broker, erhöhen Sie die Parteien, aktivieren Sie die Priorisierung von Schlüsselvitrinen.
2. Viele Schemafehler: Redrive einfrieren, Schemamigration durchführen (Backfill), mit neuer Mapper-Version neu starten.
3. Wiederholte DLQs: Batch reduzieren, „Schatten“ -Handler einschalten, Idempotenz verstärken.
4. Inkonsistenz der Vitrine: Rebuild der Vitrine aus der Zeitschrift/Quelle hinter dem Fenster durchführen (selektiv nach Tenant/Partition).
5. Hot Keys: Begrenzen Sie den Wettbewerb nach Schlüssel, fügen Sie lokale Warteschlangen hinzu und nehmen Sie das Gerät in ein separates Schaufenster.

12) Komplette Neuberechnung (Rebuild) und Backfill

Der Ansatz:
  • Stoppen Sie den Verbrauch (oder wechseln Sie zu einer neuen Version des Schaufensters).
  • In Paketen neu berechnen (nach Parteien/Daten/Tenanten).
  • Aktivieren Sie den zweiphasigen Switch: Zuerst füllen Sie' read __ v2', dann schalten Sie das Routing der Lesungen atomar um.

13) Entwicklung der Schaltungen (Versionierung)

'schema _ version' in Ereignissen/Dokumenten.
Projektion kann mehrere Versionen lesen, Migration „on the fly“.
Für große Veränderungen gibt es ein neues Schaufenster v2 und Kanarienverkehr.

14) Sicherheit und Zugang

Erben Sie RLS/ACL von der Quelle; Machen Sie das Schaufenster nicht breiter als die Originaldaten.
Maskieren Sie PIIs in Projektionen, die für UX/Analytics nicht erforderlich sind.
Auditierung von Redrives/Neuberechnungen/manuellen Bearbeitungen.

15) Konfigurationsvorlage

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) Typische Fehler

„Ein Schaufenster für alle Fälle“ → schwere Upgrades und schlechte p99.
Mangel an Idempotenz → Doppel/Sprünge in den Einheiten.
Dual-write direkt ins Schaufenster und OLTP → Unstimmigkeiten.
Null Frische → ein Konflikt der Erwartungen mit dem Produkt.
Rebuild ohne Zwei-Phasen-Switch → „Löcher“ in den Antworten.
Keine Partitionierung/Indizes → steigende Kosten und Latenz.

17) Schnelle Rezepte

Katalog/Suche: Dokumentationsvitrine + inkrementelles Upsert, Lag ≤ 5-15 c, Indizes für Filter.
Dashboards: Minuten-/Stundentanks, SUM/COUNT-Einheiten, Frische p95 ≤ 60 c.
Persönlicher Feed: Projektion nach Benutzer + causal/RYW für den Autor, Fallback pro Cache.
Global SaaS: regionale Schaufenster, Aggregate überregional; fairness per tenant.

18) Checkliste vor dem Verkauf

  • Die Vitrine ist auf eine bestimmte Anforderung ausgelegt; Es gibt Indizes und Parteien.
  • Änderungsquelle ausgewählt (Ereignisse/CDC); Liefergarantie und Schlüsselauftrag.
  • Idempotent upsert mit Versionen/Zeit; Schutz vor „alten“ Ereignissen.
  • Die Frische SLO ist definiert und wird in den Antworten gegeben ('as _ of/freshness').
  • DLQ und Secure Redrive sind konfiguriert; playbook auf rebuild/backfill.
  • Wettbewerbsbeschränkungen (per-key serial) und fairness per tenant.
  • Lag/Error/Latency-Metriken, Alerts auf p95/p99 und DLQ-Wachstum.
  • Versionierung von Schemata und Migrationsstrategie (v2 + Switch).
  • Zugriffs-/PII-Richtlinien werden vererbt und validiert.

Schlussfolgerung

Read Models und Projektionen sind ein technischer Beschleuniger für Lesungen: Sie zahlen einen kleinen Preis für „Frische“ und Streaming-Infrastruktur, um vorhersehbare Millisekunden zu erhalten und den Kern der Aufnahmen zu entlasten. Gestalten Sie Schaufenster auf Wunsch, machen Sie Upgrades idempotent, messen Sie den Lag und versprechen Sie explizit Frische - und Ihre APIs bleiben auch bei steigender Belastung, Daten und Geografie schnell.

Contact

Kontakt aufnehmen

Kontaktieren Sie uns bei Fragen oder Support.Wir helfen Ihnen jederzeit gerne!

Telegram
@Gamble_GC
Integration starten

Email ist erforderlich. Telegram oder WhatsApp – optional.

Ihr Name optional
Email optional
Betreff optional
Nachricht optional
Telegram optional
@
Wenn Sie Telegram angeben – antworten wir zusätzlich dort.
WhatsApp optional
Format: +Ländercode und Nummer (z. B. +49XXXXXXXXX).

Mit dem Klicken des Buttons stimmen Sie der Datenverarbeitung zu.