본문 바로가기

Project

결제 시나리오 3. 악의적 예약 선점

배경

악의적인 사용자가 여러 좌석을 선점한 후 결제를 진행하지 않을 경우 다른 이용자가 좌석을 예약할 수 없는 심각한 문제가 발생할 수 있습니다. 이를 해결하기 위해 결제 대기 상태에서 일정 시간이 지나면 자동으로 예약이 취소되는 시스템을 구현해야 합니다.


선택지

[RabbitMQ를 활용한 방법]

RabbitMQ는 메시지 브로커로 TTL과 DLQ(Dead Letter Queue) 기능을 활용하면 메시지를 특정 시간 동안 보관하고, 시간이 지나면 자동으로 만료되도록 설정할 수 있습니다.

구현 방식

  1. 사용자가 항공권을 예매하면 예약 메시지를 RabbitMQ의 큐에 저장하며 TTL을 설정하여 N분 후 자동 만료되도록 설정
  2. TTL이 만료되면 메시지는 Dead Letter Queue로 이동
  3. DLQ에서 메시지를 감지한 Consumer가 해당 예약을 취소하고 좌석을 해제

장점

실시간 처리 가능 - 메시지가 자동으로 만료되므로 불필요한 DB조회를 줄일 수 있음
확장성이 높음 - RabbitMQ는 분산 환경에서도 안정적으로 작동
비동기 처리 가능 - 다수의 예약을 동시에 관리할 수 있음

단점

RabbitMQ 운영 부담 - 별도의 메시지 브로커 설치, 운영, 장애 대응이 필요하고 장애 발생 시 메시지가 지연되거나 유실될 가능성이 있습니다.
Ex. RabbitMQ 서버 다운, 메시지 유실


[RedisMQ를 활용한 해결 방법]

Redis는 빠른 데이터 저장 및 조회가 가능하며 Key Expiry와 Keyspace Notification 기능을 활용하면 TTL 기반의 자동 만료 이벤트를 감지할 수 있습니다.

구현 방식

  1. 사용자가 항공권을 예매하면 Redis에 예약 정보를 저장하며 TTL을 설정하여 자동 만료되도록 함
  2. TTL이 만료되면 Redis Keyspace Notification을 통해 해당 만료 이벤트를 감지
  3. 감지된 이벤트를 처리하여 예약을 취소하고 좌석을 해제

장점

간단한 구현 - 추가적인 메시지 브로커 없이 Redis만으로 해결 가능
TTL을 활용한 자연스러운 만료 - 일정 시간이 지나면 자동으로 만료되어 데이터 정리 부담이 줄어듦

단점

이벤트 유실 가능성 - Redis Keyspace Notification이 활성화되지 않거나 장애가 발생 시 이벤트 감지가 되지 않을 수 있음. EX. Redis 서버 다운


[Spring Scheduler를 활용한 해결 방법]

Spring의 @Scheduler 기능을 활용하면 일정 주기로 DB를 조회하며 미결제된 예약을 취소하는 방식을 구현할 수 있습니다.

구현 방식

  1. 일정 주기마다 예약 테이블을 조회하여 N분 이상 결제가 진행되지 않은 예약을 찾음
  2. 해당 예약들을 자동으로 취소하고 좌석을 해제

장점

구현이 간단함 - 추가적인 메시지 브로커 없이 Spring만으로 가능
유지보수가 용이 - 예약 테이블에서 직접 상태를 변경할 수 있어 로직이 직관적

단점

대규모 트래픽에서 성능 이슈 - 예약 건수가 많아지면 주기적인 DB 조회 부담 증가
정확한 시간 제어 어려움 - 1분 이상으로 실행되면 실시간성이 떨어지고 1분 이하로 설정한다면 DB 조회에 부담이 더 극심해짐

[의사결정]

현재 프로젝트에서는 Spring의 Scheduler를 선택했습니다. 우리 시스템에서는 결제 대기 시간이 초과된 예약을 자동으로 취소하는 것이 주요 요구사항이며, 실시간성이 중요한 요구사항이 아닙니다.
RabbitMQ나 RedisMQ는 실시간 이벤트 기반으로 동작하는 장점이 있지만, 운영 부담이 크고 추가적인 학습이 필요합니다. 특히 RabbitMQ는 메시지 브로커 운영 및 장애 대응이 필요하며, RedisMQ는 Keyspace Notification 설정이 필요하고 이벤트 유실 가능성이 존재합니다.
따라서 현재 프로젝트에서는 가장 간단하면서도 안정적인 Spring Scheduler를 사용하여 일정 주기로 DB를 조회하는 방식이 최적이라는 결론을 내렸습니다.

[구현 기능]

  • 10분 이상 결제 대기 상태(IN_PROGRESS)인 예약을 자동으로 취소
  • 좌석을 다시 예매 가능 상태로 변경

결론

현재 프로젝트에서는 결제 대기 시간이 초과된 예약을 자동으로 취소하는 기능이 필요하지만,
실시간성이 필수적인 요구사항이 아니기 때문에 가장 간단하고 유지보수가 쉬운 Spring Scheduler 기반 방식을 채택했습니다.
RabbitMQ와 RedisMQ는 실시간 이벤트 처리에 유리하지만, 운영 및 설정 부담이 크고, 장애 발생 시 복구가 복잡할 수 있습니다. 반면, Spring Scheduler는 추가적인 메시지 브로커 없이도 예약 상태를 직접 조회하고 처리할 수 있어 안정적이며 유지보수도 용이합니다.
현재 10분 이상 결제 대기(IN_PROGRESS) 상태인 예약을 자동 취소하는 로직을 도입하여 좌석이 장시간 선점되는 문제를 방지할 수 있도록 하였습니다.