정확히 한 번의 의미론
정확히 한 번은
"정확히 한 번" 은 종종 두 가지 다른 것을 의미하는 것으로 이해됩니다
배송: 메시지는 정확히 한 번 소비자에게 전달됩니다.
처리: 최종 부작용 (데이터베이스에 쓰기, 잔액 변경, 다른 이벤트 발행) 은 더 많은 배송 또는 시도가 있더라도 정확히 한 번 발생합니다.
분산 시스템에서는 의미론 처리에 대해 이야기하는 것이 더 안정적입니다. 정확히 한 번 전달하기는 어렵지만 (복제 및 복제는 불가피합니다) 결과 상태는 단일 처리와 동일 할 수 있습니다.
EOS가 필요한시기와 그렇지 않은 경우
다음과 같은 경우 EOS가 필
현금 거래 및 잔액: 이중 상각이 허용되지 않습니다.
라이센스/할당량 회계, 청구 카운터.
돌이킬 수없는 외부 호출 (예: 일회성 키 활성화).
다음과 같은 경우 적어도 한 번은 + demempotency를 사용할 수 있습니다
효과는 가역적이거나 보상 가능합니다 (사가, 리턴).
임시 복제본은 상점/로그에서 허용됩니다.
트랜잭션을 전체 경로로 드래그하는 것보다 dempotent 싱크를 제공하는 것이 더 저렴합니다.
모델: 엔드 투 엔드 대 홉 바이 홉
홉-바이-홉 EOS: 각 섹션 (소스 → 프로세서 → 수신기) 은 동작이 정확히 한 번 적용되도록 보장합니다.
엔드 투 엔드 EOS: 전체 체인은 "사실" 에서 "부작용" 까지 결과가 단일 처리와 동일하도록합니다.
실제로 엔드 투 엔드는 각 홉의 트랜잭션 및/또는 demempotency의 조합으로 달성됩니다.
기본 빌딩 블록
1. Idempotent 연산
작업 키에서 동일한 쿼리를 반복하면 동일한 결과가 생성됩니다.
'deidempotency _ key '/' event _ id '/' operation _ id'.
구현: 입력 로그의 TTL
2. 읽기 프로세스 쓰기 트랜잭션
하나의 원자 작업 단위에서 부작용과 판독 진행 (오프셋/위치) 이 모두 기록됩니다. 이것은 단계 사이에 떨어질 때 "유령" 을 제거합니다.
3. Versioning/SEQUENCE
버전/카운터는 집계를 위해 저장됩니다. '예상 _ 버전' 이 일치하는 경우에만 변경 사항이 적용됩 동일한 이벤트의 반복은 버전 → 효과를 한 번 증가시키지 않습니다.
4. 중복 제거
'(소비자 _ id, 이벤트 _ id)' 또는 거래의 자연스러운 '비즈니스 _ id' 에 대한 색인.
구현 패턴
1) 오프셋 고정이있는 트랜잭션 로그 + 트랜잭션 싱크
스트림 처리에 이상적입니다.
로그에서 읽었습니다 (확인 된 항목 만).
우리는 처리를 수행합니다.
- a) 싱크대 (데이터베이스/테이블) 에 효과를 기록하십시오
- b) 수정 "N 오프셋 읽기" (동일한 데이터베이스에서).
- 커밋. 다시 시작할 때 모든 것이 할인되고 오프셋이 이동됩니다.
속성: 반복 실행은 유해하지 않습니다. 메시지를 두 번 읽더라도 "정확히 한 번" 효과가 있습니다.
2) 전송 + dempotent 소비자
거래 생산자 서비스.
하나의 데이터베이스 트랜잭션에서: 도메인 레코드를 변경하고 이벤트를 아웃 박스에 기록
리피터는 동일한 '이벤트 _ id' 로 이벤트를 버스로 전달합니다.
소비자는 이벤트를 엄청나게 적용합니다 ('이벤트 _ id' 로 정리).
속성: 생산자는 사실을 잃지 않도록합니다. 소비자는 정확히 하나의 효과를 보
3) Kafka/Flink 계열 시스템의 EOS (개념적으로)
Idempotent 프로듀서: 퇴각 보내기를 방지합니다.
생산자 거래: 주제의 항목 그룹 + 회중 교대는 원자 적으로 이루어집니다. 독자는 '읽기' 격리를 사용합니다.
처리 측은 주 상점을 저장하고 거래와 함께 커밋합니다.
속성: 저장/드래그를 다시 시작하면 이중 효과가 발생하지 않습니다. 다운 스트림에서 "보이지 않는" 복제
4) upsert/merge를 통한 Idempotent "싱크대"
Sink는 'operation _ id '/' event _ id' 를 사용하여 'UPSERT... 설명하지 않는 곳 '.
부작용 (예: 발생) 은 "아직 적용되지 않은" 검사로 원자 적으로 수행됩니다.
속성: 분산 트랜잭션없이 스토리지가있는 저렴한 EOS 방법.
주요 구현 세부 사항
트랜잭션 ID
반복에 대해 결정적이어야합니다 (수축 할 때 새 UUID를 생성하지 마십시오).
안정적인 범위를 유지하십시오 (소비자/단위/시스템).
중복 테이블
다음은 '소비자 _ id', 'operation _ id', 'application _ at', 'ttl _ represenes _ at' 입니다.
(PHP 3 = 3.0.6, PHP 4)
TTL은 최대 반복 창 (로그 보존 + 잠재적 지연) 입니다.
낙관적 인 경쟁
쓰기 모델에서 장치 버전을 저장하십시오.
이벤트/명령을 적용 할 때 'WHERE 버전 =: 예상' 을 사용하십시오. 복제본은 버전을 증가시키지 않습니다
주문/주문
EOS는 "정확히 같은 순서가 아닙니다. "배치 키 (모든 집계 이벤트 → 하나의 배치) 및/또는 '시퀀스' 비교를 통해 일관성을 유지하십시오.
이념적 인 외부 통화
안전하지 않은 방법 (예: 타사 서비스에 대한 해 웹 후크) 의 경우 'Idempotency-Key' 를 추가하고 파트너가이를 지원해야합니다.
빈번한 함정
한 곳에서만 EOS: 싱크대가 dempotent이지만 dempotency없이 2 차 이벤트를 방출하면 다운 스트림에서 "정확히 여러 번" 얻을 수 있습니다.
두 가지 커밋: 먼저 데이터베이스에서, 그 다음 오프셋 커밋은 브로커에서 커밋됩니다. 그들 사이의 추락은 중복 효과를 만듭니다.
원시 CDC 출력: DB 체계를 변경하면 소비자 demmpotency가 중단됩니다.
불안정한 키: 'operation _ id' 는 시간/무작위 및 재 트레이 중 변경에 따라 다릅니다.
비용과 절충
대기 시간: 트랜잭션/격리 된 읽기 → p95/p99 성장.
오버 헤드 스토리지: 중복 테이블, 주 상점, 트랜잭션 로그.
운영 복잡성: 트랜잭션 타임 아웃, 스레드 재조정, 막힌 세션.
진단: 더 많은 상태 ("kamit에서", "읽은대로 볼 수 있음", "롤백").
EOS 포인트 단위 선택: 중요한 집계 및 효과; 나머지는 demempotency와 보상으로 덮으십시오.
정확히 한 번 테스트
1. 결함 주입: "효과를 기록한" 단계와 "오프셋을 기록한" 단계 사이의 프로세스 감소.
2. 복제: 동일한 메시지를 2-5 번 다운로드하고 한 가지 효과를 확인하십시오.
3. 복원 및 재조정: 근로자의 정지/재시작, 이중 처리가 없는지 확인하십시오.
4. 네트워크 플래피: 중간 트랜잭션 타임 아웃, 커밋 재 시도.
5. 로드 테스트: 큐 성장 → "트랜잭션에서 영원히" 저하가 없는지 여부.
미니 템플릿 (의사)
오프셋 수정이있는 이데올로기 싱크
pseudo begin tx if not exists(select 1 from dedup where consumer_id=:c and op_id=:id)
then apply_effect(...) -- upsert / merge / add_one_time_action insert into dedup(c, id, applied_at) values(:c,:id, now)
end if update offsets set pos=:pos where consumer_id=:c commit
단위 버전으로 명령
pseudo begin tx update account set balance = balance +:delta,
version = version + 1 where id=:account_id and version=:expected_version;
if row_count=0 then error CONCURRENT_MODIFICATION commit
안전 및 준수
중복 제거 테이블의 PII/PCI: 최소값을 저장하고 원시 데이터 대신 토큰을 사용하십시오.
감사: 로그 'operation _ id', 'trace _ id', 결과 (APPLIED/ALREADY _ APPLIED).
스토리지 정책: 디드 업 테이블의 TTL, 오프셋/로그 보관.
반 패턴
"실제 정확히 한 번 전달": 영향없이 전송 프로토콜 수준에서 복제본을 제외하려는 시도.
모든 서비스를 통한 XA/2PC는 모든 것에 대한 글로벌 분산 거래가 취약하고 느립니다.
비 등식 부작용의 혼합 (예: 오프셋 커밋 전에 전송 된 전자 메일).
작동 키 부족: 페이로드의 "고유성" 에 의존합니다.
생산 점검표
- 각 중요한 효과에는 dempotent 키가 있습니다.
- 오프셋/읽기 위치는 한 트랜잭션에서 효과가 있습니다.
- 중복 표가 색인화되었습니다. TTL 로그 유지.
- 집계에 대해 낙관적 경쟁 (버전/시퀀스) 이 활성화됩니다.
- 스레드/주제는 "Comp Only" 모드에서 읽습니다 (사용 가능한 경우).
- 중복 및 드롭 테스트는 CI/CD에 있습니다.
- 대시 보드: 반복 비율, 거래 실패, 시간 차단, 지연.
- 'Idempotency-Key '/retries/timeout에 대한 통합 문서.
FAQ
거래없이 EOS를 제공 할 수 있습니까?
종종 그렇습니다-싱크대 (upsert/merge) 의 demempotency와 골재의 다양성을 통해. 거래는 보증을 단순화하지만 비용을 증가시킵니다.
모두가 정확히 한 번만 필요합니까?
아니요, 그렇지 않습니다. 비싸다. 보상이 불가능하거나 비싼 경우 포인트 단위로 적용하십시오.
문자/웹 후크를 EOS와 연결하는 방법?
커밋 전에 알림을 버퍼하고 효과를 수정 한 후 보내십시오. '알림 _ id' 를 저장하고 demempotent를 보냅니다.
더 중요한 것은 무엇입니까?
처리. 배송이 반복 될 수 있습니다. 최종 상태는 정확해야하며 유일한 상태이어야합니다.
결과
정확히 한 번은 배선에 복제본이없는 것이 아니라 효과의 정확성에 관한 것입니다. 그것은 dempotency, 효과의 원자 고정 및 읽기 진행, 합리적인 분할 및 버전 지정 규율의 조합에 의해 달성됩니다. 오류 비용을 허용 할 수없는 경우 EOS를 적용하고 낙상으로 현실을 테스트하고 운송에 대한 믿음이없는 테스트를 수행하십시오.