공공부하자개발 · 영어 학습 노트
자바
미니 프로젝트쇼핑몰 정산 시스템 4단계0/4 완료
  • 011단계: 콘솔 주문 관리 (초급 기술)
  • 022단계: 객체지향 리팩터링 (중급 기술)
  • 033단계: 모던 자바 적용 (고급 기술)
  • 044단계: 일마감 정산 배치 (배치 기술)
사이트 소개개인정보처리방침연락처
© 2026 공부하자
홈 › 미니 프로젝트 › 04 / 4

4단계: 일마감 정산 배치 (배치 기술)

섹션 6진행 0 / 4
1이번 단계의 목표2설계3구현 따라가기4실행 결과와 해설5확장 과제6다음 단계로‹ 이전다음 ›

4. 실행 결과와 해설

4.1 1차 실행 — 장애와 롤백

text
  청크  20 커밋 | 누적 읽음  20,000 처리  19,735 스킵   265 재시도 1,018
청크 40 롤백: 전원 차단 시뮬레이션 (작업 중이던 500행 폐기, 체크포인트는 청크 39 유지)
잡 비정상 종료: 전원 차단 시뮬레이션
체크포인트 상태: 청크 39, 행 39,001, 처리 38,495, 스킵 505

processChunk는 청크 40의 501번째 행(i == 500)에서 SimulatedCrash를 던진다. run의 catch (RuntimeException e)가 롤백 메시지를 찍고 다시 던지며, Main이 잡는다. 체크포인트를 다시 읽으면 청크 39, 행 39,001이다 — 청크 40의 500행은 어디에도 없다. 38,495 + 505 = 39,000 = 헤더를 뺀 39,000행이 정확히 39개 청크다.

재시도 1,018은 20,000행 중 게이트웨이를 호출한 약 19,760건의 5%인 ~988 + 2차 실패 ~49 ≈ 1,037 근처다. 해시 기반이므로 정확히 5%는 아니지만 통계적으로 맞는다.

4.2 2차 실행 — 재개

text
체크포인트 발견: 청크 39개 커밋됨, 39002행부터 재개
  청크  40 커밋 | 누적 읽음  40,000 처리  39,486 스킵   514 재시도 2,025

ChunkReader가 39,001행까지 읽고 버린 뒤 39,002행부터 청크를 만든다. 청크 40 커밋 시점의 누적이 40,000이다 — 1차 실행에서 폐기된 500행이 한 번만 반영됐다. 만약 롤백 없이 committed에 직접 집계했다면 이 시점 누적이 40,500이 됐을 것이다.

4.3 재시작 결과 == 단일 실행 결과

text
재시작 결과 == 단일 실행 결과: true

4절은 체크포인트 없이 100청크를 처음부터 돌린 straight와 result(39 + 61 청크)를 비교한다. 처리·스킵·매출·수수료·사유별 스킵이 전부 같다. 이것이 R23의 증명이다. 게이트웨이의 실패가 해시 기반이라 두 실행에서 같은 주문이 같은 시도에서 실패했기 때문에 가능하다 — Random이었다면 재시도 횟수와 RETRY_EXHAUSTED가 달라져 same이 false였을 것이다.

단, 한 가지는 같지 않다. 1차 실행에서 청크 40의 500행 중 정상 주문은 이미 게이트웨이를 호출했고, 2차 실행에서 다시 호출했다. 실제 게이트웨이라면 이중 결제다. 이 시뮬레이션은 게이트웨이가 상태를 갖지 않아 드러나지 않을 뿐이다. 해법은 멱등키(주문 ID)로 게이트웨이가 중복 요청을 거르는 것이고, 확장 과제 2에서 다룬다. 배치 레슨 04의 "재시작 가능한 잡은 멱등해야 한다"가 여기서 구체화된다.

4.4 스킵 사유 — 생성기의 오염 비율과 대조

사유 건수 생성기 비율 기대 건수 비고
QUANTITY 571 0.4% (0) + 0.2% (음수) ≈ 600 수량 0과 음수가 같은 사유로 합쳐짐
NUMBER_FORMAT 305 0.3% ≈ 300 단가 N/A
FIELD_COUNT 194 0.2% ≈ 200 결제수단 컬럼 누락 → 7컬럼
PAY_TYPE 102 0.1% ≈ 100 BITCOIN
DECLINED 95 해시 1/1000 ≈ 99 정상 주문 98,8xx건의 0.1%
RETRY_EXHAUSTED 10 0.05³ ≈ 12 3번 연속 일시 장애

합계 1,277 = 리포트의 스킵 수. 검증 스킵 4종(1,172건)은 게이트웨이를 호출하지 않았고, 결제 스킵 2종(105건)은 호출했다. 파싱 → 결제 순서 덕분에 깨진 행으로 게이트웨이를 부르는 낭비가 없다.

4.5 정산표 — 수수료 검산

text
  BANK    32,947건  매출   2,697,682,000  수수료   26,976,820  정산   2,670,705,180
  CARD    49,207건  매출   4,057,434,500  수수료  101,434,212  정산   3,956,000,288
  POINT   16,569건  매출   1,373,307,500  수수료            0  정산   1,373,307,500

BANK: 2,697,682,000 × 1.0% = 26,976,820 — 정확히 일치한다(모든 금액이 100의 배수라 절사 없음). CARD: 4,057,434,500 × 2.5% = 101,435,862.5인데 실제는 101,434,212로 1,650원 적다.

OrderRecord.fee()가 건별로 amount × 250 / 10000을 정수 나눗셈하기 때문이다(예: 2,500원 노트 1개 → 6.25 → 6). 정산에서 "합계에 요율을 곱한 값"과 "건별 수수료의 합"은 다르며, 어느 쪽이 맞는지는 계약이 정한다. 리포트는 건별 합을 쓴다.

카테고리 합계 = 결제수단 합계 = 8,128,424,000. 같은 주문을 두 축으로 집계했으니 당연히 같아야 하고, 다르면 버그다. 이런 교차 검증은 정산 리포트에 반드시 넣는다.

4.6 게이트웨이 호출 수와 소요 시간

게이트웨이 호출 수 (재개 실행): 63387. 2차 실행은 61,000행을 읽었고, 그중 검증 통과 약 60,270건 + 재시도 약 3,030회 + 거절 ~60건 ≈ 63,4xx. 재시도가 호출 수를 5% 늘렸다.

소요 시간의 대부분은 청크마다 체크포인트 파일을 쓰는 디스크 I/O(100회 쓰기 + 100회 원자적 이동)다. 파싱과 집계는 10만 행에 수백 밀리초면 끝난다. 청크 크기를 키우면 체크포인트 횟수가 줄어 빨라지지만, 장애 시 폐기되는 행이 늘어난다 — 확장 과제 3의 주제다.

실행 결과와 해설
  • 4.1 1차 실행 — 장애와 롤백
  • 4.2 2차 실행 — 재개
  • 4.3 재시작 결과 == 단일 실행 결과
  • 4.4 스킵 사유 — 생성기의 오염 비율과 대조
  • 4.5 정산표 — 수수료 검산
  • 4.6 게이트웨이 호출 수와 소요 시간
이전 섹션3 구현 따라가기4 / 6다음 섹션5 확장 과제