| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | 4 | 5 | 6 | |
| 7 | 8 | 9 | 10 | 11 | 12 | 13 |
| 14 | 15 | 16 | 17 | 18 | 19 | 20 |
| 21 | 22 | 23 | 24 | 25 | 26 | 27 |
| 28 | 29 | 30 |
Tags
- 빌더 패턴
- DB
- 트러블슈팅
- 로드밸런서
- 프록시 패턴
- Effective Java
- 계산기
- 스케줄러
- 배치
- 스프링
- 추상클래스
- 성능 개선
- 코드카타
- spring boot
- 템플릿 메서드 패턴
- redis
- java
- 자바
- Til
- 스프링 배치
- lv1
- GoF 23
- Spring Batch
- Spring
- 토스
- 프로그래머스
- 이펙티브 자바
- 백엔드
- 디자인 패턴
- 김영한
Archives
- Today
- Total
김코딩
비동기식 결제 승인 API의 응답속도 테스트 및 분석 본문
테스트 대상 API
@PostMapping("/payments/confirm")
public ResponseEntity<ApiResponse<PaymentConfirmResponse>> confirmAndChargePoint(
@RequestBody PaymentConfirmRequest request,
@AuthenticationPrincipal Auth auth) {
long startTime = System.currentTimeMillis();
PaymentConfirmResult paymentConfirmResult = paymentFacade.confirmAndChargePoint(
auth.getId(),
PaymentPresentationMapper.toPaymentConfirmCommand(request)
);
long duration = System.currentTimeMillis() - startTime;
log.info("CONFIRM API 비동기 응답 시간: {}ms", duration);
return ApiResponse.success(
HttpStatus.OK,
"포인트 충전이 완료되었습니다.",
PaymentPresentationMapper.toPaymentConfirmResponse(paymentConfirmResult));
}
- 비고: 기존의 동기 방식에서 비동기 방식으로 전환하였지만, 테스트 대상 API는 동일하게 유지됨.
- 변경의 핵심은 내부 메서드 paymentFacade.confirmAndChargePoint(...) 로직이 비동기 기반으로 변경된 점에 있음.
로직 구조 변화
Before(동기식 처리)
public PaymentConfirmResult confirmAndChargePoint(Long userId, PaymentConfirmCommand command) {
// 유저 검증
userClient.getUserById(userId);
Payment payment = null;
TossConfirmResult tossConfirmResult = null;
TossCancelResult tossCancelResult = null;
try {
// 토스 페이먼츠의 /payments/confirm API 호출 (결제 승인)
tossConfirmResult = tossClient.confirmPayment(
command.getPaymentKey(),
command.getOrderId(),
command.getAmount()
);
// 프론트에서 결제 요청한 금액과, 토스에서 실제로 결제한 금액이 일치하는지 확인
// 일치하지 않는다면 예외를 터트려서 토스 결제 취소
paymentService.validatePaymentAmount(tossConfirmResult.getTotalAmount(), command.getAmount());
// 토스 결제를 완료하고, 금액 검증을 통과하였으면 토스에서 응답받은 값을 이용하여 payment 객체 생성
payment = paymentService.createPaymentFromConfirm(userId, tossConfirmResult);
// 포인트 충전
pointClient.chargePoint(
userId,
command.getAmount(),
"CHARGE",
tossConfirmResult.getOrderId()
);
return PaymentApplicationMapper.toPaymentConfirmResult(payment);
} catch (RestClientResponseException e) {
...
}
}
- 모든 과정이 순차적 동기 처리
- 포인트 충전까지 마친 후에 응답 반환 → 상대적으로 느림
- 결제가 완료되었지만 포인트 충전에서 예외가 발생하였을 시, 결제까지 장애가 전파된다.
동기식의 응답속도 테스트 결과:
https://ddokyun.tistory.com/62
결제 승인 API의 응답속도 테스트 및 분석
테스트 대상 API@PostMapping("/payments/confirm")public ResponseEntity> confirmAndChargePoint( @RequestBody PaymentConfirmRequest request, @AuthenticationPrincipal Auth auth) { long startTime = System.currentTimeMillis(); PaymentConfirmResult paymentCo
ddokyun.tistory.com
After(비동기식 처리)
/**
* 결제 승인 및 포인트 충전 요청 처리
* 1. 사용자 검증 -> 2. 토스 결제 승인 -> 3. Payment 객체를 DONE 으로 변경 -> 4. 포인트 충전, 알림 이벤트 발행
*/
public PaymentConfirmResult confirmAndChargePoint(Long userId, PaymentConfirmCommand command) {
boolean userVerified = false;
boolean tossPaymentSucceeded = false;
TossConfirmResult tossConfirmResult = null;
Payment payment;
try {
// 유저 검증
userClient.getUserById(userId);
userVerified = true;
// 토스 페이먼츠의 /payments/confirm API 호출 (결제 승인)
tossConfirmResult = tossClient.confirmPayment(
command.getPaymentKey(),
command.getOrderId(),
command.getAmount()
);
tossPaymentSucceeded = true;
// 프론트에서 요청한 결제 금액과 토스에서 실제로 결제한 금액이 일치하는지 확인
// 일치하지 않는다면 예외를 터트린다.
// 일치한다면, 토스에서 응답받은 값을 이용하여 payment 객체 생성
payment = paymentService.markAsSuccess(
tossConfirmResult,
command.getAmount()
);
// 포인트 충전 및 알림 전송 이벤트 발행
publishPaymentCompletedEvent(payment);
return PaymentApplicationMapper.toPaymentConfirmResult(payment);
} catch (RestClientResponseException e) {
...
} catch (Exception e) {
...
}
}
- 포인트 충전 부분을 Spring 이벤트를 이용한 비동기 처리로 변경
- 결과적으로 API 응답 속도가 개선될 수 있고, 포인트에서 일어나는 장애가 결제까지 전파되는 것을 방지한다.
응답속도 테스트 방식
- 토스 결제는 테스트 코드나 부하 테스트로 검증 불가
- 실제 결제를 통해 직접 30회 수동 테스트 수행
- 측정 기준: 컨트롤러 내부에서 System.currentTimeMillis()로 응답시간 계산






























결과 분석
| 순번 | 응답시간 | 순번 | 응답시간 | 순번 | 응답시간 |
| 1 | 637ms | 11 | 567ms | 21 | 624ms |
| 2 | 624ms | 12 | 654ms | 22 | 630ms |
| 3 | 627ms | 13 | 560ms | 23 | 626ms |
| 4 | 786ms | 14 | 728ms | 24 | 617ms |
| 5 | 542ms | 15 | 679ms | 25 | 562ms |
| 6 | 569ms | 16 | 665ms | 26 | 561ms |
| 7 | 676ms | 17 | 606ms | 27 | 669ms |
| 8 | 541ms | 18 | 601ms | 28 | 606ms |
| 9 | 764ms | 19 | 626ms | 29 | 607ms |
| 10 | 550ms | 20 | 550ms | 30 | 628ms |
기본 통계 요약
| 항목 | 값 | 비고 |
| 총 샘플 수 | 30개 | |
| 평균 응답시간 | 621.6ms | |
| 최소 응답시간 | 541ms | 최고 성능 |
| 최대 응답시간 | 786ms | 상대적으로 느린 구간 |
| 표준편차 | 약 70.7ms | 비교적 안정적 |
응답시간 구간별 분포 요약
| 구간 (ms) | 건수 | 비율 |
| 541–600 | 12개 | 40.0% |
| 601–650 | 10개 | 33.3% |
| 651–700 | 6개 | 20.0% |
| 701–786 | 2개 | 6.7% |

'TIL' 카테고리의 다른 글
| 토스 결제 승인부터 포인트 충전까지의 전체 플로우 (2) | 2025.08.08 |
|---|---|
| 동기식 처리에서 비동기식 처리로 장애 격리 달성 테스트 (3) | 2025.08.07 |
| 동기식 결제 승인 API의 응답속도 테스트 및 분석 (1) | 2025.08.06 |
| 트러블슈팅 - 모든 에러가 500에러? 원인은 DTO 였다.. (0) | 2025.05.23 |
| 트러블슈팅 - 전체 일정 조회 시 N+1 문제 발생 (0) | 2025.05.21 |