モデルと予測を読む
Read Modelは、特定の製品シナリオのクイックリード用に特別に設計されたテーブル/インデックス/ビューです。Projectionは、ソースイベント/変更をRead Modelの更新(通常はidempotent upsert)に変換するプロセスです。CQRSと併用することで、OLTPコアをアンロードしてp95/p99の読み込みを安定させ「、鮮度」を制御することができます。
主なアイデア:- 「ユニバーサルスキーム」ではなく、要求に応じて非正規化します。
- 段階的かつ偶発的に更新します。
- stalenessおよび順序を明示的に管理して下さい。
1)読み取りモデルを使用する場合(およびそうでない場合)
適合:- 頻繁な重い読み取り(結合/集計/並べ替え)と許容される更新のレイテンシー。
- ダッシュボード、カタログ、ランディングページ、「top-N」、個人フィード、検索リスト。
- 負荷共有:書き込みコア-厳密な読み取り平面-高速でスケーラブル。
- 厳密な不変量を必要とする操作「エントリごとに」(お金、独自性)。強い道があります。
2)建築の概要(口頭スキーム)
1.変更のソース:OLTPからドメイン(イベントソーシング)またはCDCのイベント。
2.投影パイプライン:parser→aggregation/denormalization→idempotent upsert。
3.ストアを読んでください:クエリに最適化されたデータベース/インデックス(RDBMS、列、検索)。
4.API/client: 「as_of/freshness」属性を持つquick SELECT/GET。
3)モデル設計を読みました
クエリから始めます:どのフィールド、フィルタ、並べ替え、ペジネーション、トップN?
Denormalize:既にマージされたデータ(名前、金額、ステータス)を保存します。
- パーティショニング:'tenant_id'、 date、 region。
- 主キー:ビジネスキー+タイムバケット(例:'(tenant_id、 entity_id)'または'(tenant_id、 bucket_minute)')。
- インデックス:頻繁にwhere/order by。
- TTL/retention:一時的な表示ケース(例:90日)。
4)更新の流れおよびidempotency
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);
ルール:
- 各メッセージにはバージョン/時間が含まれます。「fresh or equal」のみを受け入れる(idempotency)。
- 集計(カウンタ、合計)の場合-状態を保存し、可換更新(またはCRDTアプローチ)を使用します。
5)変更のソース: イベントとCDC
イベント(イベントソーシング):豊富なセマンティクス、異なる投影を構築するのは簡単です。回路の進化は重要です。
CDC(論理レプリケーション):既存のデータベースに接続するだけです。DML→sobytyマッピングとノイズアップデートフィルタリングが必要になります。
- 「有毒な」メッセージの配信保証(少なくとも1回)とDLQ。
- キーによる順序(パーティションキー='tenant_id: entity_id')。
6)順序、因果性および「新鮮さ」
キーによる順序:1つのオブジェクトのイベントが順番に来る必要があります。パーティションとバージョンを使用します。
セッション/原因:著者が変更(RYW)を確認するには、クエリで透かしのバージョンを渡します。
制限されたstaleness: 'as_of'/'X-Data-Freshness'を返し、SLOを保持する(例:p95 ≤ 60c)。
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 table)のみを更新します。
- 上部の「ウィンドウ」を保存します(たとえば、セグメントごとに100〜1000行)。
8)検索とジオプロジェクション
検索(ES/Opensearch):ドキュメントの非正規化、パイプライン変換、ドキュメントのバージョン=ソースバージョン。
Geo: 'POINT/LAT、 LON'、事前集計タイル/クワッドを格納します。
9)複数のテナントおよび地域
投影キーやイベントでは'tenant_id'が必要です。
公平性:テナントごとの投影量(WFQ/DRR)を制限し「、ノイズ」が残りを遅くしないようにします。
レジデンシー:投影は書き込みコアと同じ領域に住んでいます。地域間ショーケース-集計/要約。
10)観察可能性およびSLO
メトリクス:- 'projection_lag_ms' (istochnik→vitrina)、' freshness_age_ms'(最後のデルタ以降)。
- 更新、エラー率、DLQ率、redrive成功のスループット。
- ウィンドウサイズ、p95/p99読み取りレイテンシ。
- 技術:'tenant_id'、 'entity_id'、 'event_id'、 'version'、 'projection_name'、 'attempt'。
- 注釈:ソリューションのマージ、古いバージョンの省略。
11) Playbook(ランブック)
1.遅れの成長:コネクター/ブローカーを点検して下さい、党を高めて下さい、主要なショーケースの優先順位付けを含んで下さい。
2.多くのスキーマエラー:freeze redrive、 migrate schemas (backfill)、 restart with a new version of mapper。
3.繰り返しDLQ:バッチを減らし、「shadow」ハンドラを有効にし、idempotencyを高めます。
4.ウィンドウの不整合:ウィンドウごとにログ/ソースからウィンドウを再構築します(テナント/パーティション選択)。
5.ホットキー:キーによる競争を制限し、ローカルキューを追加し、ユニットを別のショーケースに入れます。
12)完全な再集計(再構築)およびbackfill
アプローチ:- 消費を停止する(またはショーケースの新しいバージョンに切り替える)。
- バッチで再計算(バッチ/日付/テナントによる)。
- 2相スイッチを有効にする:最初に'read __ v2'を入力し、次にreadルーティングをアトミックに切り替えます。
13)回路の進化(バージョン管理)
イベント/ドキュメントの'schema_version'
投影は、その場で移行、いくつかのバージョンを読むことができます。
大きな変更-新しいV2ショーケースとカナリアトラフィック。
14)セキュリティとアクセス
ソースからRLS/ACLを継承します。元のデータよりアクセスのショーケースを広くしないで下さい。
UX/アナリティクスに不要なプロジェクションでPIIをマスクします。
redrives/recounts/manual編集の監査。
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)典型的なエラー
「すべてのケースに1つのショーケース」→重いアップデートと悪いp99。
集計におけるidempotency→duplicates/jumpsの欠如。
ショーケースとOLTP→discrepanciesに直接二重書き込み。
新鮮さのゼロ可視性→製品との相反する期待。
答えの2相スイッチ→「穴」なしで再構築します。
パーティショニング/インデックス→コストとレイテンシの増加はありません。
17)クイックレシピ
カタログ/検索:ドキュメントショーケース+増分アップサート、遅延≤ 5-15秒、フィルタのインデックス。
ダッシュボード:minute/hour tanks、 SUM/COUNTユニット、P95 freshness ≤ 60 s。
パーソナルテープ:ユーザーによる投影+著者のための因果/RYW、キャッシュへのフォールバック。
グローバルSaaS:地域のショーケース、地域横断的な集約;テナントごとの公平性。
18)売り上げ前のチェックリスト
- ショーケースは特定の要求のために設計されています;指数とパーティーがあります。
- 選択した変更元(イベント/CDC);配達保証およびキー順序。
- バージョン/時間のIdempotent upsert;「古い」出来事に対する保護。
- 鮮度SLOは定義され、答えられます('as_of/freshness')。
- DLQとセキュアリリースが構成されています。rebuild/backfillのplaybook。
- テナントごとのキーごとのシリアルと公平性。
- Lag/error/latencyメトリクス、p95/p99アラート、およびDLQの増加。
- 回路のバージョン管理と移行戦略(v2+スイッチ)。
- Access/PIIポリシーは継承され、検証されます。
結論
Readモデルと予測は、読み取りのエンジニアリングアクセラレータです。予測可能なミリ秒を取得し、録音のコアをオフロードするために、「新鮮さ」とストリーミングインフラストラクチャのための小さな価格を支払います。リクエストに合わせてストアフロントを設計し、アップデートをアイドル状態にし、ラグを測定し、鮮度を明確に約束します。APIは負荷、データ、地理の増加にもかかわらず高速です。