Czytaj modele i projekcje
Czytaj Model jest specjalnie zaprojektowaną tabelą/indeksem/widokiem dla szybkich odczytów dla konkretnego scenariusza produktu. Projekcja to proces konwertujący zdarzenia źródłowe/zmiany do aktualizacji Read Model (zwykle idempotent upsert). W połączeniu z CQRS pozwala to rozładować rdzeń OLTP i ustabilizować odczyty p95/p99, kontrolując „świeżość”.
Główne pomysły:- Denormalizować na żądanie, a nie „uniwersalny schemat”.
- Aktualizuj stopniowo i idempotentnie.
- Wyraźnie zarządzaj stalością i porządkiem.
1) Kiedy używać modeli odczytu (a kiedy nie)
Pasuje do:- Częste odczyty ciężkie (połączenia/agregacje/rodzaje) z dopuszczalnym opóźnieniem aktualizacji.
- Deski rozdzielcze, katalogi, strony lądowania, „top-N”, kanały osobiste, listy wyszukiwań.
- Współdzielenie obciążenia: rdzeń zapisu - ścisły, czytelny - szybki i skalowalny.
- Operacje wymagające ścisłych stałych „na wejście” (pieniądze, wyjątkowość). Jest silna droga.
2) Zarys architektoniczny (schemat słowny)
1. Źródło zmian: zdarzenia domeny (event sourcing) lub CDC z OLTP.
2. Rurociąg projekcyjny: parser → agregacja/denormalizacja → idempotent upsert.
3. Przeczytaj sklep: baza danych/indeks zoptymalizowany dla zapytania (RDBMS, kolumna, wyszukiwanie).
4. API/client: quick SELECT/GET, z atrybutami „as_of/freshness”.
3) Przeczytaj wzór
Zacznij od zapytania: które pola, filtry, sortowanie, paginacja, top N?
Denormalizuj: Przechowywać już połączone dane (nazwy, kwoty, statusy).
- Podział: przez 'lokator _ id', data, region.
- Klucz podstawowy: klucz biznesowy + wiadro czasowe (na przykład „(tenant_id, entity_id)” lub „(tenant_id, bucket_minute)”).
- Indeksy: przez częste miejsce/zamówienie przez.
- TTL/retencja: dla czasowych przypadków wyświetlania (np. 90 dni).
4) Aktualizacja przepływu i idempotencji
Idempotent upsert jest podstawą stabilności projekcji.
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);
Zasady:
- Każda wiadomość zawiera wersję/godzinę; akceptować tylko „świeże lub równe” (idempotencja).
- Dla agregatów (liczniki, sumy) - przechowywać stan i używać aktualizacji commutative (lub podejścia CRDT).
5) Źródło zmian: Wydarzenia vs CDC
Wydarzenia (event sourcing): bogata semantyka, łatwo jest zbudować różne projekcje; ewolucja obwodów jest ważna.
CDC (replikacja logiczna): wystarczy połączyć się z istniejącą bazą danych; DML → wymagane będzie mapowanie sobyty i filtrowanie aktualizacji szumów.
- Gwarancje dostawy (przynajmniej raz) i DLQ dla „trujących” wiadomości.
- Kolejność według klucza (klucz partycji = 'lokator _ id: entity _ id').
6) Porządek, przyczynowość i „świeżość”
Kolejność według klucza: zdarzenia jednego obiektu muszą przychodzić kolejno; używać partycji i wersji.
Sesja/przyczyna: Aby autor mógł zobaczyć ich zmiany (RYW), podaj wersje znaków wodnych w zapytaniach.
Ograniczona stalowość: powrót' as _ of "/" X-Data-Freshness "i trzymać SLO (np. p95 ≤ 60c).
7) Kruszywa przyrostowe i górne N
Przykład minutowych wiader sprzedaży: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;
Dla Top N:
- Utrzymuj ranking prezentacji (na przykład przez 'revenue DESC') i aktualizuj tylko zmienione pozycje (hałas/skiplist/ograniczona tabela).
- Przechowywać „okno” góry (na przykład 100-1000 linii na segment).
8) Wyszukiwanie i geo-projekcja
Wyszukiwanie (ES/Opensearch): znormalizowany dokument, przekształcenia rurociągu, wersja dokumentu = wersja źródłowa.
Geo: sklep „POINT/LAT, LON”, płytki/quady wstępnie zagregowane.
9) Wieloosobowy najemca i regiony
'lokator _ id' jest wymagany w kluczykach projekcyjnych i zdarzeniach.
Uczciwość: ograniczyć przepustowość rzutów na najemcę (WFQ/DRR), aby „hałas” nie spowalniał reszty.
Rezydencja: projekcja mieszka w tym samym regionie co rdzeń pisma; międzyregionalne prezentacje - agregaty/podsumowania.
10) Obserwowalność i SLO
Metryka:- „projection _ lag _ ms” (istochnik → vitrina), „freshness _ age _ ms” (od ostatniej delty).
- przepustowość aktualizacji, szybkość błędów, szybkość DLQ, redrive-sukces.
- Rozmiar okna, opóźnienie odczytu p95/p99.
- Тера: 'tenant _ id',' entity _ id', 'event _ id',' version ',' projection _ name ',' attempt '.
- Adnotacje: rozwiązania scalające, pominięcie przestarzałych wersji.
11) Playbooks (książki startowe)
1. Opóźnienie wzrostu: sprawdź złącze/broker, zwiększyć partie, zawierać priorytety kluczowych prezentacji.
2. Wiele błędów schematu: zamrożenie redrive, migracja schematów (backfill), ponowne uruchomienie z nową wersją mapera.
3. Powtarzane DLQ: zmniejszyć partię, włączyć obsługę „cieni”, zwiększyć idempotencję.
4. Niespójność okna: odbudować okna z dziennika/źródła na okno (lokator/partycja selektywna).
5. Hot keys: ograniczyć konkurencję o klucz, dodać lokalne kolejki, umieścić jednostkę w osobnej prezentacji.
12) Pełne przeliczenie (odbudowa) i zasypka
Podejście:- Zatrzymaj zużycie (lub przełącz na nową wersję prezentacji).
- Przeliczyć w partiach (według partii/daty/najemcy).
- Włącz przełącznik dwufazowy: najpierw wypełnić 'read __ v2', a następnie atomowo przełączyć odczytaną trasę.
13) Ewolucja obwodów (wersioning)
„schema _ version” w wydarzeniach/dokumentach.
Projekcja może odczytać kilka wersji, migrację na muchę.
Dla dużych zmian - nowa prezentacja v2 i ruch kanaryjski.
14) Bezpieczeństwo i dostęp
Dziedzicz RLS/ACL ze źródła; nie czynią prezentacji szerszym w dostępie niż oryginalne dane.
Maska PII w projekcjach niepotrzebnych do UX/analityki.
Audyt rededycji/recount/edycji ręcznych.
15) Szablon konfiguracji
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) Typowe błędy
„Jeden pokaz dla wszystkich przypadków” → ciężkie aktualizacje i zły p99.
Brak idempotencji → duplikaty/skoki w kruszywach.
Dual-write bezpośrednio do prezentacji i OLTP → rozbieżności.
Zero widoczności świeżości → sprzeczne oczekiwania z produktem.
Odbudować bez przełącznika dwufazowego → „dziury” w odpowiedziach.
Brak podziału/indeksów → wzrost kosztów i opóźnień.
17) Szybkie przepisy kulinarne
Katalog/wyszukiwanie: prezentacja dokumentów + przyrostowy upsert, lag ≤ 5-15 s, indeksy dla filtrów.
Deski rozdzielcze: zbiorniki minutowe/godzinne, jednostki "SUM/COUNT', świeżość p95 ≤ 60 s.
Taśma osobista: projekcja przez użytkownika + przyczynowy/RYW dla autora, wpadka do pamięci podręcznej.
Globalny system SaaS: regionalne prezentacje, agregaty międzyregionalne; uczciwość na najemcę.
18) Lista kontrolna przedsprzedaży
- Prezentacja jest przeznaczona do konkretnego wniosku; są indeksy i partie.
- Wybrane źródło zmian (zdarzenia/CDC); gwarancje dostawy i kluczowe zamówienie.
- Idempotent upsert z wersjami/czas; ochrona przed „starymi” wydarzeniami.
- Świeżość SLO jest zdefiniowana i odpowiadana („as _ of/freshness”).
- Skonfigurowane DLQ i Secure Release; playbook on rebuild/backfill.
- Na klucz seryjny i uczciwość na najemcę.
- Wskaźniki lag/error/latency, alerty p95/p99 i wzrost DLQ.
- Strategia weryfikacji obwodów i migracji (v2 + switch).
- Polityki dostępu/PII są dziedziczone i zatwierdzone.
Wnioski
Czytaj Modele i projekcje są inżynierskim akceleratorem odczytów: płacisz niewielką cenę za „świeżość” i infrastrukturę strumieniową, aby uzyskać przewidywalne milisekundy i odciążyć rdzeń nagrań. Projektowanie sklepów, aby dostosować się do Twojej prośby, uczynić aktualizacje idempotentne, zmierzyć opóźnienie i wyraźnie obiecać świeżość - a Twoje interfejsy API pozostaną szybkie nawet przy rosnącym obciążeniu, danych i geografii.