GH GambleHub

閱讀模型和投影

Read Model是一種專門設計的表格/索引/視圖,用於針對特定產品腳本進行快速閱讀。投影是將事件/源更改轉換為Read Model更新(通常為idempotent upsert)的過程。與CQRS結合,這允許卸載OLTP內核並穩定p95/p99讀數,從而控制「新鮮度」。

主要想法:
  • 根據請求而不是「通用方案」進行非規範化。
  • 增量和偶數更新。
  • 明確地管理穩定和秩序。

1)何時使用Read Models(何時不使用)

適合:
  • 頻繁重讀(joins/聚合/排序),有效的更新延遲。
  • Dashbords,目錄,登陸,「top-N」,個人圍裙,搜索列表。
  • 負載分離:寫入核心-嚴格,讀取平面-快速且可擴展。
不合適:
  • 需要嚴格的「每個條目」不變量的操作(金錢,唯一性)。那裏有一個堅強的路徑。

2)建築輪廓(言語方案)

1.更改源:來自OLTP的域事件(事件源)或CDC。
2.投影輸送機:解析器→ aggregation/去規範化 → idempotent upsert。
3.Read Store:針對查詢優化的DB/索引 (RDBMS、柱形、搜索)。
4.API/客戶端:快速SELECT/GET,具有「as_of/freshness」屬性。

3) Read Model設計

從查詢開始: 哪些字段、過濾器、排序、分頁、前N?

去規範化:存儲已經合並的數據(名稱、金額、狀態)。

鑰匙:
  • 派對:通過「tenant_id」,日期,區域。
  • 主要鑰匙:業務密鑰+時間桶(例如「(tenant_id,entity_id)」或「(tenant_id,bucket_minute)」)。
  • 索引:按頻率where/order by。
  • TTL/重建:用於臨時店面(例如90天)。

4)更新流程和平均水平

Idempotent upsert是投影穩定性的基礎。

偽造的:
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);
規則:
  • 每個消息都帶有版本/時間;僅接受「新鮮或平等」(idempotency)。
  • 對於聚合體(計數器、和)-存儲狀態並使用交換式更新(或CRDT方法)。

5)更改源: 事件vs CDC

事件(事件來源):豐富的語義,易於構建不同的投影;圖的演變很重要。
CDC(邏輯復制):簡單地連接到現有數據庫;需要模擬DML→sobyty並過濾噪音升級。

這兩種選擇都需要:
  • 「有毒」消息的交付保證(at least-once)和DLQ。
  • 按鍵排序(partition key='tenant_id: entity_id')。

6)順序,因果關系和「新鮮」

按鍵順序:一個對象的事件必須依次出現;使用派對和版本。
因果關系(session/causal):讓作者看到他們的變化(RYW),在查詢中傳遞水印版本。
新鮮(bounded staleness):返回「as_of」/「X-Data-Freshness」並保持SLO(例如p95 ≤ 60 c)。

7)增量單元和前N

分鐘銷售箱示例:
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;
對於前N:
  • 維護排名的店面(例如「revenue DESC」),並且僅更新更改的位置(heap/skiplist/limited)。
  • 存儲頂部的「窗口」(例如每段100-1000行)。

8)搜索和地理投影

搜索(ES/Opensearch):非歸一化文檔、轉換管道、文檔版本=源版本。
Geo:存儲「POINT/LAT, LON」,預聚合針腳/四邊形。

9)多特南特和地區

「tenant_id」在投影鍵和事件中具有約束力。
Fairness:限制per tenant投影(WFQ/DRR),以便「嘈雜」不會抑制其他投影。
居住地:投影與寫核生活在同一區域;區域間店面-總結/摘要。

10)可觀察性和SLO

度量標準:
  • 「projection_lag_ms」 (istochnik→vitrina)、「freshness_age_ms」(自上次三角洲以來)。
  • 通過升級,錯誤比例,DLQ-rate, redrive-success.
  • 店面大小,p95/p99閱讀潛伏期。
Tracing/Logs:
  • Теги: `tenant_id`, `entity_id`, `event_id`, `version`, `projection_name`, `attempt`.
  • 註釋:merge解決方案,跳過舊版本。

11)花花公子(runbooks)

1.拉格增長:檢查連接器/經紀人,增加分期付款,包括重點展示的優先級。
2.許多模式錯誤:凍結重做,執行模式遷移(backfill),重新啟動新版本的mapper。
3.重復DLQ:減少擊球,啟用「影子」處理程序,增強等效性。
4.店面不一致:從每窗口的日誌/來源執行重構店面(選擇性tenant/partition)。
5.熱鍵:限制按鍵競爭,添加本地隊列,將單元帶到單獨的店面。

12)完全重新計票(rebuild)和backfill

方法是:
  • 停止消費(或切換到新版本的店面)。
  • 用包重新計算(按批次/日期/tenants)。
  • 啟用兩階段卷軸:首先填充「read __ v2」,然後原子切換讀取路由。

13)方案的演變(轉化)

事件/文檔中的「schema_version」。
投影可以讀取多個版本,「即時」遷移。
對於重大變化-新的v2展示櫃和金絲雀流量。

14)安全和訪問

從源位置繼承RLS/ACL;不要在訪問方面比原始數據更廣泛。
將PII偽裝成不需要UX/分析的投影。
審核紅路/重新計票/手動編輯。

15)配置模板

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)典型錯誤

「每個案例一個展示櫃」→嚴重的升級和壞的p99。
單位→雙打/跳躍缺乏等效性。
雙寫直接進入店面和OLTP →差異。
零新鮮度可見性→與產品的期望沖突。
Rebuild沒有兩相卷軸→答案中的「孔」。
沒有分期付款/指數→價值上升和潛伏期上升。

17)快速食譜

目錄/搜索:文檔展示+增量upsert,lag ≤ 5-15 c,篩選器的索引。
Dashbords:分鐘/小時垃圾箱,「SUM/COUNT」單元,p95新鮮度≤ 60 c。
個人磁帶:作者按用戶+causal/RYW投影,後退到緩存。

全球SaaS: 區域店面,跨區域分組;fairness per tenant.

18)售前支票清單

  • 陳列櫃的設計符合特定的要求;有指數和分期付款。
  • 選擇更改源(事件/CDC);交付保證和按鍵順序。
  • 具有版本/時間的Idempotent upsert;防止發生「舊」事件。
  • 在答復(「as_of/freshness」)中定義並給出了新鮮度的SLO。
  • DLQ和安全的重新分區配置;rebuild/backfill上的花花公子。
  • 競爭限制(按鍵串行)和公平競爭限制。
  • 滯後/錯誤/後退度量,p95/p99上的差值和DLQ的增長。
  • 回收方案和遷移策略(v2+switch)。
  • 訪問策略/PII已繼承和驗證。

結論

閱讀模型和投影是一種工程閱讀加速器:您付出「新鮮度」和流媒體基礎架構的少量代價,以獲得可預測的毫秒並卸載記錄核心。在查詢下設計店面,使升級變得令人望而生畏,測量時差,並明確承諾新鮮-即使負載,數據和地理位置增加,您的API仍將保持快速。

Contact

與我們聯繫

如有任何問題或支援需求,歡迎隨時聯絡我們。我們隨時樂意提供協助!

開始整合

Email 為 必填。Telegram 或 WhatsApp 為 選填

您的姓名 選填
Email 選填
主旨 選填
訊息內容 選填
Telegram 選填
@
若您填寫 Telegram,我們將在 Email 之外,同步於 Telegram 回覆您。
WhatsApp 選填
格式:國碼 + 電話號碼(例如:+886XXXXXXXXX)。

按下此按鈕即表示您同意我們處理您的資料。