요구사항
교육 시스템 내 그룹 결제 기능과 부분 결제 취소 기능을 구현해야 했습니다.
기능구현 과정 중 여러 문제점을 발견하였습니다.
- 보안 검증 로직 미흡
- 결제 히스토리 및 교육 히스토리 누락
해당 부분의 개선이 필요하다 판단하여 결제 시스템을 리펙토링 하게 되었습니다.
분석
환경 및 현재 처리하고 있는 환경에 대해 분석하였습니다.
문제
이중 큰 문제점을 분석하여 아래와 같이 정의했습니다.
환경
L4 로드벨런서 뒤로 WAS1, 2에서 동일한 Application이 돌아가고 있는 분산 모놀리식 구조로 DB의 경우 단일 DB를 사용하고 있는 환경으로 분석했습니다.
현 교육 시스템의 경우 트래픽이 매우 낮은 편이며 결제 또한 하루 0에서 많으면 10건정도로 적은 상태로 확인됩니다.
현재 프록시서버 내에서 이용중인 프록시 서버가 없습니다.
PG사 환경 설정 또한 백오프에 대해서와 원자성은 어떻게 보존되며 주요 주문정보들에 대한 중복결제의 로직은 어떻게 처리되는지에 대해 분석하였습니다.
백오프 : 10분 주기
중복 주문번호처리 : 24간 내의 주문번호는 PG사 내에서 차단
문제해결
분석 내용을 토대로 하나씩 원인을 규명하고 해결을 진행할 것이다.
결제 파라미터 위변조
원인
결제 금액을 클라이언트 측에서 보내진 값을 검증하지 않은채로 결제를 진행하도록 처리되는 이슈를 확인하였습니다. 이렇게 될 경우 클라이언트에서 인위적으로 금액을 설정하여 서버측으로 금액을 보내면 서버는 그대로 인식하여 해당 값으로 결제를 진행하게 됩니다.
해결
public JSONObject createEncryptData(PaymentApiRequestVo paymentApiRequestVo,
HttpServletRequest request) throws Exception {
// .....request 값에 대한 데이터 가공
paymentService.VerifyService(vo); // 데이터 검증 로직
JSONObject result = paymentService.encryptData(vo); // 데이터 암호화
return result;
}해당 문제가 결제 모듈 전반에 영향을 미치므로 서버내에 하나의 공통 Service를 생성하여 검증로직을 관리하도록 추가 조치를 진행하여 서버 검증 로직을 구현하였습니다. 이를 통해 금액에 대한 원자성을 보장할 수 있게 되었습니다.
Network Retry 및 동시성
원인
더블 클릭 혹은 네트워크 재시도를 통한 중복실행에 대해 동시에 동일한 데이터 값이 처리되었을 경우에 대해 처리되는 로직이 없는것으로 확인되었습니다.
결제 취소 혹은 결제 되었을 경우 두 번 로직이 실행되어 기존 데이터가 덮어써지는 케이스가 발생할 수 있습니다.
해결
결제 취소와 결제에서 멱등성을 보장하여 동일한 처리시 동일한 응답만 보내도록 수정하였습니다.
결제
PG사 내에서 제공하는 위젯을 통해 결제를 하기 때문에 결제 프로세스의 경우 webHook으로 들어오는 데이터를 대상으로 멱등성을 체크하게 된다 만약 처리하지 않을경우 백오프에 의해 재시도 되는 데이터가 중복 처리되어 원자성을 훼손할 수 있기 때문에 처리가 필연적입니다.
결제 취소
결제 취소의 경우 PG사 내에선 Non-UI를 제공 즉 API를 제공하기 때문에 IETF 에서 제공하는 멱등성 표준을 기준으로 처리를 진행하였습니다.
클라이언트에게 멱등키를 헤더에서 제공받아 Intercaptor에서 해당 요청을 체크한다 만약 있을 경우 그대로 이전 데이터를 return 하여 클라이언트에게 일관된 응답을 제공합니다.
하지만 현재 환경에선 Redis를 고려하고 있지 않습니다.
이에 다른 고려사항으로 트래픽이 낮다는점, 단일 DB를 사용하고 있다는 점을 고려하여 DB Unique 키를 이용하여 다중 서버 트랜잭션 관련 문제를 해결하였습니다.
마치며..
외부 api 환경, 네트워크 상태, 현재 서버의 환경까지 종합적으로 신경쓰며 최상의 시나리오를 설계하는것에 대해 여러 기술중 채택의 사유가 명확해야함을 알게된 프로젝트였습니다.
💬 댓글 0
불러오는 중...