메시지 순서 보증
1) "주문" 이란 무엇이며 왜 필요한가
메시지 순서는 한 엔티티 (주문, 사용자, 지갑) 또는 전체 스트림의 이벤트에 대한 "전에 처리해야 할 것" 관계입니다. 불변자에게는 중요합니다: "B 이전 상태", "상각 전 균형", "n + 1 이전 버전".
분산 시스템에서 전 세계 총 주문은 비싸고 거의 필요하지 않습니다. 로컬 키당 주문으로 충분합니다.
2) 질서 보장 유형
1. 파티션 당 (로그 섹션의 로컬 순서) -Kafka: 당사자 내 순서는 당사자 간에 유지됩니다.
2. 키 당 (키/메시지 그룹 주문) -하나의 키가있는 모든 메시지는 하나의 "스레드" 처리 (Kafka key, SQS FIFO MessageGroupID, Pub/Sub 주문 키) 로 라우팅됩니다.
3. 전 세계 총 순서-전체 시스템에는 단일 순서 (분산 저널/시퀀서) 가 표시됩니다. 비용이 많이 들고 가용성과 처리량이 저하됩니다.
4. 인과 순서- "B가 효과를 관찰하면 A 이후의 이벤트 B" 글로벌 시퀀서없이 메타 데이터 (버전, Lamport 시간/벡터 시계) 를 통해 회복 할 수 있습니다.
5. 최선의 노력 주문-중개인은 주문을 유지하려고 시도하지만 실패시 순열이 가능합니다 (종종 NATS Core, RabbitMQ에서 여러 소비자가 있음).
3) 주문이 무너지는 곳
동일한 큐의 병렬 소비자 (RabbitMQ: 큐당 여러 소비자 → 인터리빙).
배달/재 배달 (적어도 한 번), 'ack' 타임 아웃, 다시 큐잉.
재 균형/페일 오버 (Kafka: 파티/리더 이동).
DLQ/재 처리-" 유독 한 "메시지는 DLQ로갑니다. 다음 메시지는 추가 → 논리적 중단입니다.
다중 영역 및 복제-다른 지연 → 오정렬.
4) 주요 주문 설계
핵심은 "주문 단위" 를 형성합니다. "권장 사항:- 자연 키 사용: 'order _ id', 'wallet _ id', 'colligate _ id'.
- "핫 키" 를보십시오. 하나의 키는 흐름을 "차단" 할 수 있습니다 (헤드 오브 라인 차단). 필요한 경우 키를 나눕니다. 'order _ id # shard (0.. k-1) '은 싱크대에서 순서를 결정 론적으로 재구성합니다.
- Kafka-하나의 키 → 하나의 부분에서 순서는 키 내에 보존됩니다.
java producer.send(new ProducerRecord<>("orders", orderId, eventBytes));
(Key = 'orderID' 는 로컬 주문을 보장합니다.)
5) "주문 대 대역폭"
강력한 보증은 종종 처리량 및 가용성과 충돌합니다
대기열 당 한 명의 소비자가 주문을 유지하지만 동시성을 줄입니
적어도 한 번 + 동시성은 성능을 향상 시키지만 demempotency 및/또는 재정렬이 필요합니다.
글로벌 주문은 시퀀서에 홉 → latentnost 및 실패 위험에 홉을 추가합니다.
타협: 키 당 순서, 병렬 처리 = 당사자/그룹 수, + dempotent 타박상.
6) 특정 중개인의 주문 통제
카프카
파티 내에서 주문.
관찰 '최대. 에서. 비행. 요청. per. 연결을 사용할 수 있습니다. 생산자의 배상금이 순서를 변경하지 않도록 demempotence = 참 '.
소비자 그룹: 한 당사자 → 한 번에 한 명의 근로자. 반복 배송이 가능합니다 → 비즈니스 계층에서 시퀀스/버전을 유지하십시오.
읽기 프로세스 쓰기 트랜잭션은 읽기/쓰기/부스러기 오프셋 일관성을 유지하지만 글로벌 주문을 만들지는 않습니다.
properties enable.idempotence=true acks=all retries=2147483647 max.in.flight.requests.per.connection=5
RabbitMQ (AMQP)
주문은 하나의 여름 동안 하나의 대기열로 보장됩니다. 메시지의 여러 소비자와 함께 "혼합" 될 수 있습니다.
순서대로: 완료되면 하나의 consummer 또는 prefetch = 1 + ack. 동시성의 경우 키별로 분리 된 대기열 (샤딩 교환/일관된 해시 교환).
NATS/제트 스트림
NATS Core-최선의 노력, 낮은 대기 시간, 주문이 방해 될 수 있습니다.
JetStream: 스트림/시퀀스 내에서 주문; 재배송 중에 콘솔의 재 배열이 가능합니다. → 시퀀스 및 복구 버퍼를 사용할 수 있습니다.
SQS FIFO
정확히 한 번 처리 (효과적으로 중복으로 인해) 및 MessageGroupID 내의 순서. 동시성-헤드 라인 그룹 내 그룹 수.
구글 펍/서브
주문 키는 키 내에서 주문을 제공합니다. 오류가 발생하면 복원 될 때까지 게시가 차단됩니다. 역압을 조심하십시오.
7) 순서 보존 및 복원 패턴
7. 1 시퀀스/버전 지정
각 이벤트에는 'seq '/' 버전' 이 있습니다. 회중:- 'seq = last _ seq + 1' 인 경우에만 이벤트를 수행합니다.
- 그렇지 않으면 누락 된 버퍼가 도착하기 전에 대기 버퍼를 넣으십시오 ('last _ seq + 1').
pseudo if seq == last+1: apply(); last++
else if seq > last+1: buffer[seq] = ev else: skip // дубль/повтор
7. 버퍼 및 창 2 개 (스트림 처리)
시간 창 + 워터 마크: 워터 마크에 따라 창을 "닫고" 정렬합니다.
지연 시간 허용: 늦게 도착할 수있는 채널 (재 컴파일/무시).
7. 키별로 3 끈적 끈적한 라우팅
해시 (키)% 파편 해시 라우팅은 모든 주요 이벤트를 단일 작업자에게 보냅니다.
Kubernetes에서-L4 HTBalancer가 아닌 대기열/sherds 레벨에서 세션 (고정) 을 유지합니다.
7. 4 배우 모델/" 키당 하나의 스트림 "
중요한 집계 (지갑) 의 경우: 배우가 순차적으로 처리하고 나머지 병렬 처리-배우의 수.
7. 5 Idempotence + 재정렬
질서가 회복되더라도 반복이 가능합니다. 키 + 버전과받은 편지함으로 UPSERT를 결합하십시오 (정확히 한 번 vs 최소 한 번 참조).
8) "독" 메시지로 작업 (독 약)
"하나의 메시지가 처리되지 않으면 어떻게 살아야합니까?"
엄격한 순서: 키 흐름 차단 (SQS FIFO: 전체 그룹). 솔루션은 키별로 DLQ입니다. 문제 키/그룹 만 별도의 큐/수동 구문 분석으로 전송합니다.
유연한 주문: 건너 뛰기/보상이 가능합니다. 우리는 로그인하고 계속합니다 (금융/임계 집계가 아님).
재 트레이 정책: 제한된 'max-advery' + backoff + avidempotent 효과.
9) 다중 지역 및 글로벌 시스템
클러스터 연결/복제 (Kafka) 는 지역 간 글로벌 주문을 보장하지 않습니다. 로컬 키당 주문 및 demmpotent 타박상을 우선시하십시오.
진정한 글로벌 순서의 경우 시퀀서 (중앙 로그) 를 사용하지만 이는 가용성 (CAP: 네트워크 중단의 경우 A 빼기) 에 영향을줍니다.
대안: 일부 도메인 (카운터, 세트) 에 대한 인과 순서 + CRDT-엄격한 순서가 필요하지 않습니다.
10) 순서의 관찰 가능성
(PHP 3 = 3.0.6, PHP 4)
11) 반 패턴
키를 깎지 않고 한 대기열 + 많은 소비자-주문이 즉시 분류됩니다.
dempotency없이 동일한 대기열에서 다시 공개하여 두 배로 증가합니다.
전 세계 "경우에 따라" 순서는 실질적인 이점이없는 대기 시간과 가치의 폭발입니다.
SQS FIFO는 모든 그룹을위한 하나의 그룹입니다. 키 당 MessageGroupId를 사용하십시오.
"핫 키" 를 무시하십시오-하나의 "지갑" 은 모든 것을 느리게합니다. 가능한 경우 키를 하위 키로 나눕니다.
동일한 대기열/그룹에서 중요 및 벌크 스트림을 혼합-상호 영향 및 순서 상실.
12) 구현 점검표
- 키/파티션 당/인과/글로벌?
- 시퀀싱 키 및 핫 키 전략이 설계되었습니다.
- 라우터 구성: 파티셔닝/MessageGroupID/주문 키.
- 콘솔은 열쇠 (끈적 끈적한 라우팅, 파편 작업자) 에 의해 분리됩니다.
- 타박상에 대한 이데올로기 및/또는받은 편지함/UPSERT가 포함되어 있습니다.
- 시퀀스/버전 구현 및 버퍼 재정렬 (필요한 경우).
- 주요 정책 및 백오프 배상에 의하여 DLQ.
- 주문 외, 차단 된 _ keys, 늦은 _ 이벤트 순서 및 경고 메트릭스.
- 게임 데이: 재조정, 노드 손실, 유독 한 메시지, 네트워크 지연.
- 문서: 순서 불변, 창 경계, SLA에 미치는 영향.
13) 설정 예
13. 1 카프카 소비자 (주문 위반 최소화)
properties max.poll.records=500 enable.auto.commit=false # коммит после успешной обработки батча isolation.level=read_committed
13. 2 RabbitMQ (동시성 가격 별 주문)
대기열 당 하나의 소비자 + '기본. qos (프리 페치 = 1) '
동시성-여러 대기열 및 해시 교환:bash rabbitmq-plugins enable rabbitmq_consistent_hash_exchange публикуем с хедером/ключом для консистентного хеша
13. 3 SQS FIFO
메사지그룹 = 키를 설정합니다. 동시성 = 그룹 수.
복제물로부터 보호하기위한 MessageDeduplicationID (공급자 창에서).
13. 4 NATS JetStream (주문 소비자, 스케치)
bash nats consumer add ORDERS ORD-KEY-42 --filter "orders.42.>" --deliver pull \
--ack explicit --max-deliver 6
키> 응용 프로그램에서 '시퀀스' 를 모니터링하고 버퍼를 재정렬합니다.
14) FAQ
Q: 글로벌 주문이 필요합니까?
A: 거의 없습니다. 거의 항상 키로 충분합니다. 전 세계 질서는 비싸고 경제성이 뛰어납니다.
Q: 엄격한 순서로 "유독 한" 메시지는 어떻습니까?
A: 키/그룹 만 DLQ로 이전하면 나머지는 계속됩니다.
Q: 동시에 주문과 규모를 확장 할 수 있습니까?
A: 예, 키 주문 + 많은 키/부품 + dempotent 작업 및 필요한 경우 버퍼 재정렬.
Q: 더 중요한 것은: 주문 또는 정확히 한 번입니까?
A: 대부분의 도메인-키 오더 + 효과적으로 정확히 한 번의 효과 (dedempotency/UPSERT). 운송은 적어도 한 번은 가능합니다.
15) 총계
주문은 비싼 글로벌 규율이 아니라 비즈니스 키에 대한 지역 보증입니다. 키 및 파티를 설계하고 핫 키를 제한하며 demempotence를 사용하고 필요한 경우 시퀀스 + 재정렬 버퍼를 사용하십시오. 순서가 맞지 않고 차단 된 키 메트릭, 테스트 충돌을 조심하면 성능이나 가용성을 희생하지 않고 예측 가능한 처리를받을 수 있습니다.