예약하기 수정 - f-lab-edu/at_ticket GitHub Wiki
예약하기 - 예약방식
개요
저희 티켓 예약 서비스에서 핵심인 예약하기 기능을 구현하기 위해서 다른 서비스들의 예약 방식들을 한번 찾아보았습니다.
크게 2가지 방식이 있었습니다.
1. 결제 여부와 상관 없이 먼저 좌석을 선택한 사용자에게 결제 우선권을 부여한 후에 시간 안에 결제되면 예매가 확정되는 방식
2. 결제까지 완료해야 예매와 좌석 선택이 확정되는 방식
1. 먼저 좌석을 선택한 사용자에게 결제 우선권을 부여하는 방식
장점으로는 같은 좌석에 대해서 동시에 결제하는 경우를 배제할 수 있기 때문에 비교적 쉬운 구현이라고 생각했습니다.
단점으로는 사용자 입장에서 좌석을 계속 결제하지 않고 예약할 수 있기 때문에 계속 예약 좌석을 선점하여 악용할 수가 있습니다.
따라서 사용자 별로 미결제인 예약 좌석 수를 제한하고, 결제 마감시간을 부여하여 결제가 늦어지는 예약 건에 대해서 자동으로 예약 취소가 되도록 하는 기능들을 부수적으로 만들어야 하는 단점이 있습니다.
(이후 이 방식을 '선좌석 예약방식
'이라고 지칭하겠습니다.)
2. 결제까지 완료해야 좌석 선택이 확정되는 방식
장점은 직관적인 예약방식으로 앞서 전자의 방식에 비해 부수적으로 만들어야 하는 부분이 없습니다.
단점은 다수의 사용자가 동시에 결제 요청을 한 경우에 대해서 신경쓸 부분이 많습니다.
결제완료가 늦은 사용자들에게는 다시 환불 되도록 하는 구조는 사용자 경험을 떨어트리므로 결제가 진행이 되지 않도록 해야하고, 결제가 외부 시스템일 경우 트랜잭션 처리가 복잡하기 때문에 구현 난이도가 높다는 단점이 있습니다.
(이후 이 방식을 '선결제 예약방식
'이라고 지칭하겠습니다.)
저희의 선택
저희는 외부 결제 시스템을 사용할 예정입니다. 후자의 선결제 예약방식
를 선택한다면 복잡한 트랜잭션 처리가 필요하고 기능을 안정적으로 구현하는데에 시간이 많이 들 것이라 판단되어 전자인 선좌석 예약방식
을 채택했습니다.
선좌석 예약방식 프로세스
선좌석 예약방식
의 프로세스는 아래와 같습니다.
-
1단계. 좌석 선택 가능 여부 확인
-
예약 가능한 좌석인 경우,
Pre-reservation 테이블
에 선택 좌석 정보를 저장합니다.Reservation 테이블
에 예약 상태를 "결제 대기 상태
"로 변경 합니다.
-
예약 가능한 좌석이 아닌 경우
- 에러 처리
-
-
2단계. 결제 모듈 호출해서 결제를 진행합니다.
- 결제에 성공한 경우
- 결제 정보를 리턴 받고, 다음 단계로 진행합니다.
- 결제에 실패한경우
- 에러 처리
- 결제에 성공한 경우
-
3단계. 예약 확정
- 예약 데이터와 결제 모듈 영수증 데이터가 일치하는 경우,
Pre-reservation 테이블
의 선택 좌석 정보를 삭제합니다.Reservation 테이블
의 예약 상태를 "예약 완료 상태
"로 변경 합니다.
- 예약 데이터와 결제 모듈 영수증 데이터가 일치하지 않으면
결제 취소
후 에러 처리
- 예약 데이터와 결제 모듈 영수증 데이터가 일치하는 경우,
Pre-reservation 테이블
은 선택 좌석 정보를 임시 저장하는 테이블로써,
결제가 정상적으로 완료된 건의 좌석 정보는 지워집니다.
고려사항
만약 결제 도중 구매자가 결제창을 꺼버리는 등의 결제가 제대로 완료되지 않은 상황이 발생한다면?
Reservation 테이블
의 상태값이 결제 대기 상태
의 예약 건인 경우, Pre-reservation 테이블
의 좌석 선택 후 경과한 시간을 확인하여 일정 시간이 지났다면 예약을 취소한 것으로 간주할 수 있습니다.
Pre-reservation 테이블의
의 저장된 좌석은 삭제하고, Reservation 테이블
의 상태값을 원복시켜주면 다른 구매자가 그 좌석을 구매할 수 있게 됩니다.
좌석 예약 동시 요청
좌석을 동시에 예약하는 경우에 대해서는 중복되는 데이터가 발생하지 않도록,
어떤 공연인지를 나타내는 show_id
와 특정 좌석을 나타내는 seat_id
ID 두개로 이루어진 복합키로 PK
를 걸어서 특정 공연의 특정 좌석에 해당 되는 데이터는 DB에 한 건 밖에 저장될 수 없도록 조치하였습니다.
+ 내용 추가
멀티 쓰레드를 이용한 테스트 코드를 사용하여, 여러 사용자가 동시에 같은 좌석을 예약하려고 할 때의 상황을 가정하여 테스트를 해보니,
이미 다른 사용자가 선예약을 완료하였음에도 불구하고, 다른 사용자가 선예약을 하려고 시도하는 동시성 문제가 발생하였습니다.
동시성 문제 해결에 관한 고민을 해보고 추가로 글을 작성하였습니다.
링크 (예약하기 동시성 제어)
결제 정보 조작
결제 모듈의 호출을 front 쪽에서 하기 때문에 악성 사용자가 결제 가격을 조작하는 등의 정보를 조작할 가능성이 있다고 판단하였습니다.
그래서 예약 API에서 '좌석 Id', '공연 Id', '사용자 Id'로 이루어진 좌석 정보와, '예약 좌석의 가격'과 '영수증 데이터의 가격' 가격 정보에 해당하는 데이터를
예약 데이터와 영수증 데이터의 정보를 상호 비교
하여, 조작된 정보로 예약 되는 일 이없도록 방지책을 마련했습니다.
좌석을 선점한 고객이 결제를 하지 않는 경우
좌석을 선점한 고객이 결제를 하지 않는 경우, 해당 고객이 계속 좌석에 대한 우선권을 가지고 있게 해선 안됩니다. 따라서 미결제 예약에 대한 삭제 처리가 필요하다고 생각했습니다.
5분의 결제 시간을 주고 결제 마감 시간이 경과하면 좌석 예약 데이터를 삭제하는 배치 프로그램을 추가하여 해결할 예정입니다.