본문 바로가기
프로젝트/개인 프로젝트 V3

거래요청에 대한 동시성 테스트

by Thumper 2024. 12. 6.

주문시 트랜잭션처리와 예외처리에 대한 생각

상품 거래 시스템을 만들 때 신경 써야 하는 부분이 많았었습니다.
그 중에서 동시성 관리는 중요한 요구사항 중 하나였습니다.
주문 처리 시 상품이 단일 상품으로 정의되었기 때문에, 동시에 주문 요청이 들어오는 상황에서 동시성 제어가 필요했습니다.

특히, 다수의 사용자가 동시에 주문을 시도할 경우 데이터 무결성을 보장해야 했습니다.
단일 상품으로 재고가 1개이기에 중복 거래요청이 발생하면 구매자와 판매자 모두에게 곤란한 상황을 만들게 됩니다.

주문 생성 및 판매 요청처리 단계에서 트랜잭션을 어떻게 사용해야 할지 고민했습니다.
이번 시간에는 동시성 문제를 해결한 과정을 다루겠습니다.

주문 처리 흐름에서의 트랜잭션과 예외처리

리포지토리 인터페이스

image
JPA에서 제공하는 비관적 락을 사용하여 중복 거래 요청을 방지하기로 했습니다.
이를 위해 데이터베이스에 쓰기 락을 설정하는 PESSIMISTIC_WRITE 옵션을 적용했습니다.
주문 요청 처리 과정에서, 해당 상품에 대한 주문이 이미 들어왔는지 트랜잭션 내에서 확인하고 락을 설정함으로써 중복 거래 요청을 방지할 수 있었습니다.

서비스 로직

image

주문요청 서비스 로직을 구현할 때, 비관적 락이 적용된 메서드를 호출하여 동시에 주문요청이 들어오는 경우를 처리하려고 했습니다.
해당 서비스 메서드는 @Transactional을 적용하여 트랜잭션을 관리했습니다.

주문 처리 중 발생할 수 있는 예외 상황을 안전하게 관리하기 위해 try-catch 블록을 활용했습니다.
이 과정에서 특정 예외 상황에 대해 로그를 남기고, 필요 시 적절한 예외를 발생시키도록 구현했습니다.

테스트 코드

image

2명의 구매자가 동시에 같은 상품에 대해 거래를 요청을 가정해서 테스트 코드를 작성했습니다.
한 명만 성공하고 나머지 한 명은 실패하게 되는지 확인했습니다.

동시성 문제 해결을 위해 ExecutorService와 CountDownLatch를 사용해 여러 스레드를 동기화하고, 비관적 락을 통해 안전하게 처리되는지 확인하는 방법을 사용했습니다.
failCount.get()가 1인지를 확인하여, 한 명의 구매자만 성공적으로 거래에 참여했는지 검증했습니다.

후기

포스팅 글에 첨부된 코드는 프로젝트 Github 여기로 확인하실 수 있습니다.
이번 프로젝트 요구사항을 구현하기 위해, 트랜잭션과 락을 사용하고 try-catch로 예외 상황을 다루어 보았습니다.
읽어주셔서 감사합니다:)

댓글