CQRS 및 읽기/쓰기 분리
CQRS 란 무엇입니까
CQRS (명령 쿼리 책임 분리) 는 데이터 모델과 작성 (명령) 및 읽기 (쿼리) 를 담당하는 구성 요소를 분리하는 아키텍처 방식입니다.
아이디어: 상태 변경 프로세스는 유효한 불변량 및 트랜잭션, 빠르고 표적화 된 프로젝션 및 스케일링에 대한 읽기에 최적화되어 있습니다.
키> 명령은 상태를 변경하고 작업 결과를 반환합니다. 요청은 읽을 수 있으며 부작용이 없습니다.
왜 필요합니까?
성능 읽기: 특정 시나리오 (테이프, 보고서, 카탈로그) 에 대한 구체화 된 프로젝션.
중요한 경로 안정성: "무거운" 결합 및 집계에서 분리 된 기록.
스토리지 선택의 자유: 작성을위한 OLTP, 읽기를위한 OLAP/캐시/검색 엔진.
가속화 된 진화: 거래를 "파괴" 할 위험없이 새로운보기를 추가하십시오.
관찰 및 감사 (특히 이벤트 소싱과 함께): 상태를 복구하고 재생하는 것이 더 쉽습니다.
신청시기 (그리고 그렇지 않은 경우)
다음과 같은 경우 적합합
데이터 슬라이스와 복잡한 집계가 다른 읽기가 우선합니다.
중요한 기록 경로는 미묘하고 예측 가능해야합니다.
읽고 쓰기 위해서는 다른 SLO/SLA가 필요합니다.
분석/검색 요구에서 도메인 쓰기 논리를 분리해야합니다.
다음과 같은 경우 적합하지 않습니
모든 시나리오에서 읽기와 쓰기 사이의 강력한 일관성이 필수적
도메인은 간단하고 하중이 낮습니다. CRUD 코프.
팀은 경험이 없으며 운영 복잡성은 용납 할 수 없습니다.
기본 개념
명령은 상태를 변경하는 경향이 있습니다 ('CreateOrder', 'CapturePayment'). 불변량을 확인하십시오.
쿼리 검색 데이터 ('GetOrderByID', 'ListUserTransactions'). 부작용이 없습니다.
기록 모델: 집계/불변/거래; 스토리지 - 관계형/키 값/이벤트 로그.
읽기 (투영) 모델: 구체화 된 테이블/인덱스/캐시, 비동기식으로 동기화됩니다.
일관성: 종종 녹음과 읽기 사이에; 필기 모델에서 직접 읽음을 통한 중요한 경로.
건축 (골격)
1. 쓰기 서비스: 명령을 수락하고 불변량을 검증하며 변경 사항 (데이터베이스 또는 이벤트) 을 캡처합니다.
2. 전송/CDC: 변경 사실의 게시 보장.
3. 프로젝션 프로세서: 이벤트/CDC를 듣고 읽기 모델을 업데이트하십시오.
4. 읽기 서비스: 실제보기/캐시/검색에서 쿼리를 제공합니다.
5. 사가/오케스트레이션: 교차 집계 프로세스 조정.
6. 관찰 가능성: 투영 지연, 성공적인 응용 프로그램 백분율, DLQ.
녹음 모델 설계
집계: 명확한 트랜잭션 경계 (예: '주문', '지불', 'UserBalance').
불변량: 공식화 (금전적 금액 0, 독창성, 한계).
명령은 키별로 demotent입니다 (예: 'idempotency _ key').
거래 범위는 최소입니다. 외부 부작용-아웃 박스를 통한.
명령 예 (Pseudo-JSON)
json
{
"command": "CapturePayment",
"payment_id": "pay_123",
"amount": 1000,
"currency": "EUR",
"idempotency_key": "k-789",
"trace_id": "t-abc"
}
읽기 모델 디자인
쿼리부터 시작: 어떤 화면/보고서가 필요합니까?
읽기 모델- "최적화 된 캐시" 와 같은 비정규화가 허용됩니다.
검색 (OpenSearch), 보고서 (columnar storage), 카드 (KV/Redis) 와 같은 다양한 작업에 대한 여러 프로젝션.
TTL 및 재 조립: 투영은 소스에서 복구 할 수 있어야합니다 (이벤트 재생/스냅 샷).
일관성과 UX
최종 일관성: 인터페이스는 짧은 시간 동안 오래된 데이터를 표시 할 수 있습니
UX 패턴: "데이터가 업데이트됩니다"..., 낙관적 UI, 동기화 지표, 확인 될 때까지 위험한 동작을 차단합니다.
강력한 일관성이 필요한 작업 (예: 쓰기 전에 정확한 균형을 보임) 의 경우 쓰기 모델에서 직접 읽으십시오.
CQRS 및 이벤트 소싱 (옵션)
이벤트 소싱 (ES) 은 이벤트를 저장하며 집계 상태는 컨볼 루션의 결과입니다.
CQRS + ES 번들은 이상적인 감사와 예측을 쉽게 재 조립할 수 있지만 복잡성을 증가시킵니다.
대체: 일반 OLTP 데이터베이스 + 아웃 박스/CDC → 프로젝션.
복제: 전송 및 CDC
미리 보기 (한 번의 트랜잭션으로): 도메인을 작성하면 이벤트를 아웃 박스로 변경하고 이벤트를 작 출판사가 타이어에 배달합니다.
CDC: 데이터베이스 로그 (Debezium 등) 에서 읽기 → 도메인 이벤트로의 변환.
보증: 기본적으로 적어도 한 번은 소비자와 프로젝션이 유쾌해야합니다.
스토리지 선택
쓰기: 트랜잭션을위한 관계형 (PostgreSQL/MySQL); KV/문서-불변량이 간단한 곳.
읽기:- KV/Redis-카드 및 빠른 키 판독;
- 검색 (OpenSearch/ElasticSearch) -검색/필터/패셋;
- 열 (클릭 하우스/빅 쿼리) -보고서;
- CDN의 캐시 - 공개 디렉토리/컨텐츠.
통합 패턴
API 계층: '명령' 및 '쿼리' 에 대한 별도의 엔드 포인트/서비스.
이념성: 헤더/본체의 작동 키; TTL을 사용한 최신 키 저장.
사가/오케스트레이션: 타임 아웃, 보상, 단계 반복성.
역압-프로세서의 병렬 처리를 제한합니다.
관찰 가능
쓰기 지표: p95/99 명령 대기 시간, 성공적인 트랜잭션 백분율, 검증 오류.
메트릭 읽기: p95/99 요청, 적중률 캐시, 검색 클러스터에로드.
프로젝션 지연 (시간 및 메시지), DLQ 비율, 중복 제거 비율.
추적: 'trace _ id' 는 → 아웃 박스 명령 → → 쿼리 투영을 통과합니다.
안전 및 준수
권리 분리: 글쓰기와 읽기를위한 다른 범위/역할; 최소한의 특권의 원칙.
PII/PCI: 투영에서 최소화; 휴식/기내 암호화; 마스킹.
감사: 팀, 배우, 결과, 'trace _ id' 수정; 중요한 도메인 (결제, KYC) 을위한 WORM 아카이브.
테스트
계약 테스트: 명령 (오류, 불변) 및 쿼리 (형식/필터).
투영 테스트: 일련의 이벤트/CDC를 제출하고 최종 읽기 모델을 확인하십시오.
혼돈/대기 시간: 프로젝션 프로세서에 대기 시간 주입; 지연시 UX 점검.
재생성: 스냅 샷/로그에서 스탠드의 프로젝션을 다시 조립합니다.
이주와 진화
회로를 재 설계 할 때 이중 쓰기; 전환 할 때까지 오래된 투영을 유지하십시오
새로운 필드-이벤트/CDC의 첨가제; 읽기 모델이 재구성됩니다.
버전: 'v1 '/' v2' 이벤트 및 엔드 포인트, 일몰 계획.
기능 플래그: 카나리아를 따라 새로운 쿼리/프로젝션 도입.
반 패턴
간단한 CRUD 서비스에서 CQRS "패션을 위해".
하드 동기식 읽기 쓰기 종속성 (격리 및 지속성을 해제).
모두를위한 하나의 색인: 이기종 쿼리를 하나의 읽기 저장소로 혼합.
투영에는 demempotency → 중복 및 불일치가 없습니다.
복구 불가능한 프로젝션 (재생/스냅 샷 없음).
도메인의 예
결제 (온라인 서비스)
쓰기: 거래 데이터베이스에서 '승인', '캡처', '환불'; 아웃 박스는 결제를 게시합니다. '.
읽기:- UI에 대한 Redis "결제 카드";
- 보고를위한 ClickHouse;
- 트랜잭션을 검색하기 위한 OpenSearch.
- 중요한 경로: 인증 UI - 최종 (최대 2-3 초) 의 일관성을 읽습니다.
KYC
쓰기: 상태 시작/업데이트 명령; 보안 데이터베이스에 PII 스토리지.
읽기: PII가없는 상태의 경량 투영; 필요한 경우 PII를 포인트 단위로 조입니다.
보안: 읽기 상태 및 문서 액세스에 대한 다른 범위.
대차 대조표 (iGaming/Finance)
쓰기: 원자 증분/감소가있는 'UserBalance' 집계; 수술을위한 dempotent 열쇠.
읽기: "빠른 균형" 에 대한 캐시; 쓰기-쓰기에서 직접 읽기 (엄격한 일관성).
사가: 예금/결론은 실패의 경우 보상에 의해 조정됩니다.
구현 점검표
- 쓰기 모델의 집계 및 불변량이 강조됩니다.
- 주요 쿼리가 정의되고 투영이 설계되었습니다.
- 전송/CDC 및 demempotent 프로젝션 프로세서가 구성됩니다.
- 스냅 샷/재생 계획이 있습니다.
- SLO: 명령 대기 시간, 투영 지연, 읽기/쓰기 가용성 별도.
- 별도의 액세스 권한 및 데이터 암호화가 구현되었습니
- DLQ 경고/지연/중복 제거 오류.
- 테스트: 계약, 투영, 혼돈, 재생.
FAQ
CQRS에 이벤트 소싱이 필수입니까?
아니요, 그렇지 않습니다. 일반 데이터베이스 + 아웃 박스/CDC에서 빌드 할 수 있습니다.
비동기화를 다루는 방법?
명시 적으로 UX를 설계하고 투영 지연을 측정하며 중요한 작업을 쓰기에서 읽도록하십시오
동일한 서비스에서 쓰기와 읽기를 모두 유지할 수 있습니까?
예, 물리적 분리는 선택 사항입니다. 논리적 책임 분담은 필수입니다.
집계 간의 거래는 어떻습니까?
사가와 사건을 통해; 가능하면 분산 거래를 피하십시오
결과
CQRS는 손을 풀어줍니다. 명확한 불변량을 가진 얇고 신뢰할 수있는 쓰기 경로와 구체화 된 프로젝션의 빠른 표적 읽기. 이것은 일관성, 관찰 성 및 이주가 훈련되면 생산성을 높이고 진화를 단순화하며 시스템을 스트레스에보다 탄력적으로 만듭니다.