반복 전략 및 dempotency
1) 왜 필요한가
네트워크에서 타임 아웃, 일시적 오류, 네트워크 플래핑, 과부하 등 장애가 표준입니다. Retreats는 다음과 같은 경우에만 신뢰성을 향상
1. 안전을 반복하십시오 (dempotent)
2. 반복 사이의 지연이 관찰됩니다
3. 한계/할당량 및 중독 "건강" 이 존중됩니다.
목표는 잘못된 테이크와 레이스없이 비즈니스 운영 수준에서 효과적으로 한 번의 행동입니다.
2) 전달 의미론의 분류
최대 한 번에: 반복 없음, 손실 위험 (로깅, 화재 및 잊어 버림).
적어도 한 번: 중복이 가능합니다 → 소비자 demempotence가 필요합니다 (대부분의 대기열, 웹 후크).
효과적으로 한 번: 중복이 가능하지만 올바르게 중복됩니다 (키, 트랜잭션, 아웃 박스).
3) 철회 시점과 그렇지 않은시기
퇴각은 '408', '429' ('Redch-After' 관찰), '425' (Too Early), '499' (클라이언트가 주변에서 닫힘), '5xx', '504', 네트워크 타임 아웃/브레이크, 게이트웨이에서 '502', "연결 재설정".
쿼리를 변경하지 않고 철회하지 마십시오: '400/401/403/404/422'.
논란의 여지가있는 사례: '409 충돌' (일반적으로 retrayim이 아님); 먼저 작업 상태를 읽거나 의도를 재확인 함).
4) 타임 아웃, 백오프 및 지터
4. 1 규칙
첫 번째 타임 아웃, 복고풍: 각 요청에는 "마감일" 이 있어야합니다.
지수 백오프: 'delay _ n = base 2 ² n', 한계 'max _ delay'.
지터가 필요합니다: "둔한 동기파" 를 분리하기 위해 임의성을 추가하십시오.
4. 2 지터 패턴
전체 지터: 'sleep = rand (0, base2 ² n)' 가 전반적인 선택입니다.
장식 된 지터: 긴 대화 상자에 대한 'sleep = min (max _ delay, rand (base, sleep _ prev3))' -
동일한 지터: 'sleep = base2 ² n/2 + rand (0, base2 ² n/2)' -부드러운 변형.
4. 3 재시도 예산
배송 비율을 제한하십시오
'재 시도 _ budment _ per _ min = max (α success _ rps, floor β)'; 일반적으로 'α = 0. 1–0. 2`.
예산이 소진되면 실패/회로 차단기로 "열기" 로 전환하십시오.
5) 속도 제한 및 회로 차단기와의 상호 작용
'Redch-After', 'RateLimit-Reat' 을 존중하고 백오프로 계산하십시오.
높은 '5xx '/타임 아웃에서 리트레이 주파수와 전체 동시성이 낮아집니다.
- 하프 오픈: 제한된 샘플링을 허용합니다.
- 열기: 즉시 거부합니다 (리소스 저장).
- 휴무: 일반 작업.
- 쓰기 작업에서는 공격적인 배신보다 명확한 힌트로 409/503을 반환하는 것이 좋습니다.
6) 쓰기 작업의 이념성
6. 1 일반적인 아이디어
같은 의도 → 하나의 결과. 기본은 dempotence 키와 실행 레코드 저장입니다.
6. 2 HTP 계약
클라이언트가 헤더를 보냅니다:
Idempotency-Key: 7a6b7f9e-2a46-4d0b-9c3a-2b30e1c3c9e3
Idempotency-Key-Expiry: 24h # optional
서버:
- 첫 번째 성공에 대한 저장 (키, 결과 → 상태, 바디 해시)
- 반복되면 이전 응답과 헤더 'Idempotency-Replay: 참' 을 반환하십시오.
- 신체 충돌 (동일한 키이지만 다른 페이로드) 의 경우-' 409 충돌 '.
6. 3 스토리지 및 TTL
테이블/값 키: 'dedempotency _ key', '요청 _ hash', '결과', '상태', '만료 _ at'.
TTL = 가능한 재생 및 늦은 배송의 창 (일반적으로 지불의 경우 24-72 시간).
'idempotency _ key' 별 지수; 높은로드의 경우-해시 샤딩.
6. 4 예 스키마 (SQL)
sql
CREATE TABLE idempo_store (
key UUID PRIMARY KEY,
req_hash BYTEA NOT NULL,
status INT NOT NULL,
response JSONB NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
expiry_at TIMESTAMPTZ NOT NULL
);
6. 5 핸들러 의사 코드
pseudo handle_write(req):
k = req. headers["Idempotency-Key"]
h = hash(req. body)
rec = idempo_store. get(k)
if rec and rec. req_hash == h:
return rec. status, rec. response, {"Idempotency-Replay": "true"}
if rec and rec. req_hash!= h:
return 409, problem("IDEMPOTENT_CONFLICT")
begin tx result = apply_business_mutation (req) # change status upsert once (idempo_store, key = k, req_hash=h, status = 201, response = result, expiry = now () + 2d)
commit
return 201, result
7) "효과적으로 한 번" 패턴
거래 전송: 비즈니스 이벤트를 기록하고 배경 릴레이를 통해 동일한 데이터베이스 트랜잭션에서 메시지를 보냅니다. 소비자는 demmpotent입니다.
소비자의받은 편지함/가공 테이블: 중복을 무시하기 위해 '이벤트 _ id' 를 저장하십시오.
카프카 (Kafka) 에서 정확히 한 번 정확하게 한 번: 생산자/소비자 EOS의 경우에도 적용 논리는 여전히 엄청나게해야합니다.
보상 거래 (Saga): 단계가 철회되고 부작용이 발생하면 시스템을 불변으로 되돌립니다.
8) 특별한 경우: 지불 및 금융 거래
강력한 dempotency: 키는 작업 로직에 바인딩됩니다 (예: '외부 _ payment _ id').
PSP에서의 중복 제거 - 상점 '상인 _ 참조' → 반복되면 PSP는 동일한 결과를 반환합니다.
"클라이언트로부터" 배상: 'Idempotency-Key', 그렇지 않으면 이중 상각의 위험이있는 경우에만 허용하십시오.
경쟁: 실행 기간 동안 "계정/도구/계약" 을 잠급니다. 반복되면 409/423을 반환하십시오.
관찰 가능성: 메트릭 'idempo _ replay _ total', 'idempo _ glam _ total'.
9) 웹 후크 및 외부 과제
HMAC 서명 및 시간 창; 먼저 검증 한 다음 처리합니다.
Sender retrays: 지수 백오프 + 지터, 'max _ trides' 및 DLQ.
소비자 - dem 등원: '이벤트 _ id' → 테이블/인 메모리 캐시; "깔끔한" 주문이 보장되지 않습니다.
코드: 2xx = 성공, 4xx = 반복하지 않음, 5xx/타임 아웃 = 반복.
10) 대기열 및 배경 작업
기본적으로 한 번 이상 → 복제본은 불가피합니다.
'태스크 _ id '/' 이벤트 _ id' 및 실행 상태를 저장합니다. 복제본-짧은 경로 "재생".
DLQ 및 독 메시지: 시도 카운터, 검역, 수동 분석.
경쟁 제한 (세마포어) 및 demmpotent 작업자.
11) Versioning 및 "natural" 키
자연 키 (계정 번호 + 날짜 + 문서 번호) 는 반복 저항을 증가시킵니다.
스키마/버전을 변경할 때 'Idempotency-Key' 에 버전 키를 포함 시키십시오.
12) STP 헤더와 클라이언트에 프롬프트
'Idempotency-Key', 'Idempotency-Replay', 'Re폐기', '선호: 대기 = <sec>' (긴 작업), 'If-Match '/' ETag' (낙관적 잠금 장치).
주요 충돌 425/429/503의 경우 유효한 '재생 후' 와 409입니다.
"긴" 작업의 경우 - 비동기 상태 수신 (상태 자원 당 '202 허용' + '위치').
13) 테스트 및 혼돈 시나리오
부정적인 테스트: 이중 전송, 다른 신체와의 반복, 시계 비 동기화.
순서가 맞지 않음: 't2' 가 't1' 보다 먼저옵니다.
타임 아웃/' RST '/' EOF ', 절반 요청 (slow-POST).
타락한 demempotency 스토리지 → 실패 동작 (이중 쓰기보다 실패).
14) 지표 및 경고
(PHP 3 = 3.0.6, PHP 4)
(PHP 3 = 3.0.6, PHP 4)
노선별로 409/425/429/5xx를 공유하십시오. 후퇴와 함께 p95/p99 "성공의 시간".
경고: 연소 속도 재 트레이 예산, dempotence 충돌의 급증, DLQ 성장.
15) 안티 패턴
모든 실수를 연속으로 줄입니다.
지터 부족 → 동기식 복귀 파.
TTL 및 청소가없는 수명이 긴 키.
부작용 커밋 후 결과 저장 (아웃 박스 위반).
'trace _ id '/' dedempotency _ key' 가없는 로그는 → 생성 할 수 없습니다.
쓰기 작업에 대한 공격적인 병렬 재구성.
16) Prod 준비 점검표
- 통합 정책: 무엇을 되풀이하고, 그렇지 않은가; 코드 및 고객 프롬프트.
- 지수 백오프 + 풀 지터; (PHP 3 = 3.0.6, PHP 4)
- TTL로 계약 'Idempotency-Key' + 결과 저장.
- 이벤트에 대한 전송/받은 편지함; DLQ; 경쟁 한계.
- 회로 차단기와의 통합, '재시도 후' 를 존중하십시오.
- 리트레이/중복/충돌에 의한 메트릭/경고.
- 일련의 혼돈 테스트 및 네트워크 장애 에뮬레이션.
- 고객 문서-백업 및 상태의 예.
17) TL; DR
후퇴는 demempotency와 함께 만 유용합니다. 'Idempotency-Key' 를 입력하고 결과 스토리지를 입력하고 지터 및 재 시도 예산으로 기하 급수적 인 백오프를 적용하십시오. 이벤트의 경우-아웃 박스/받은 편지함; 지불, 엄격한 중복 제거 및 잠금. 측정 배상 및 충돌, 테스트 중복 및 타임 아웃.