개발일지

실시간 경매 / 한정 판매 프로젝트

오늘도개발 2024. 11. 25. 16:27

 

* 2024.07 ~ 2024.11 진행

 

프로젝트 개요

 

 이번 프로젝트는 동시성, 장애 발생시 처리, Cache 와 DB 의 정합성, Test 코드 작성을 중심으로 진행하였다.  Front는 Html과 bootstrap, Javascript( jQuery )를 이용하여 개발하였고 Thymeleaf를 통하여 뷰를 구성하였다. Thymeleaf의 문법 및 기능은 최대한 사용을 지양하고 AJAX 을 통하여 비동기 통신으로 Restful하게 구현하였다.

 

* 팀 구성은 BE 3명으로 구성되었고 다음과 같이 역할을 분담

 

팀원1 : 로그인, 회원가입, 채팅

팀원2 : 한정 판매 기능

본인 : 경매 기능

 

 

 

 목차 ( 클릭시 해당 위치 이동)

1. 프로젝트 소개

 

2. 시스템 아키텍쳐

 

3. 예외 처리

   - Transaction Rollback 관리

   - DB와 Cache간 데이터 정합성 관리

 

4. 동시성 문제 처리

   - Redisson 을 이용한 Distributed Lock 처리

   - Log를 통한 데이터 히스토리 관리

 

5. Schedular 와 Batch를 이용한 경매 입찰 완료 처리

   - Schedular을 이용하여 다음날 00 시에 입찰 완료 처리

   - Batch를 이용하여 한번에 여러 경매 처리

 

6. 테스트 코드를 통한 확인

   - 예외 발생 시 Trasaction 및 Cache 정합성 확인

   - 동시 요청 시 정합성 확인

  

7. 회고

 

 1. 프로젝트 소개

 

Auction

 

 

경매에 사전 예치금을 등록하고 경매에 참여해보세요 ! 지정된 경매 시간에 입찰을 할 수 있습니다.

     경매 제품 구매 처리는 경매 종료일 다음날 자정 00 시 이후부터 진행됩니다.

 

경매는 실시간으로  채팅을 바탕으로 진행 됩니다.

     @ 가격으로 입찰 가능하며 자신이 등록한 예치금 내 금액으로만 가능합니다.

 

 

 2. 시스템 아키텍쳐 

 

 이번 프로젝트는 경매 프로젝트를 통하여 동시에 요청이 온 경우, 포인트 이동중 장애가 발생한 것을 대처하는 것에 중점적으로 진행하였다.

 

 

  * 이번 프로젝트는 DB 정합성과 예외 발생시 처리에 대한 것을 중점적으로 진행하였으므로

    배포 및 실제 2개 이상의 서버를 운용한 프로젝트에 대해서 궁금하다면 실전 프로젝트(떠나볼까)를 참고

 

 

 

 

 3. 예외 처리

 

 예외 발생 시, 기본적으로 RuntimeException을 상속받은 Custom Exception을 사용하여 보다 구체적인 예외 상황을 처리할 수 있도록 설계하였다. 또한, Spring의 @RestControllerAdvice를 이용하여 Global Exception Handler를 생성하고, 모든 예외를 중앙에서 관리할 수 있도록 구현하였다. 에러 메시지는 HTTP 상태 코드(HttpStatus)와 메시지 형식을 포함한 Custom Error 클래스를 별도로 설계하여, 클라이언트가 항상 일관된 형식의 에러 메시지를 받을 수 있도록 구현하였다.

 

 

  예외 발생 시 우려 사항 및 해결 방안

 

1. Transaction Rollback

 서비스와 서비스 간에 각각 별도의 트랜잭션이 존재할 경우, 뒤에서 실행되는 서비스에서 예외가 발생하면 앞서 실행된 서비스의 Transaction이 Rollback되지 않을 가능성이 있다. 이러한 문제를 방지하기 위해 Transaction Propagation을 설정하여 트랜잭션 간 연결을 보장하는 방법이 있다. 하지만, 트랜잭션을 지나치게 오래 유지하면 데이터베이스 커넥션이 과도하게 점유되어 성능 저하를 초래할 수 있다. 이를 예방하기 위해 서비스를 단위 기능으로 세분화하여 Transaction 범위를 최소화 한다. 또한 서비스와 서비스가 연결될 경우 해당 서비스를 관리하는 상위 서비스를 생성하고 Transaction을 관리한다

 

2. DB와 Cache간 데이터 불일치 문제

Global Cache(Redis)를 사용하고 있으므로, 데이터베이스(DB)Cache 간 데이터가 일치하지 않는 문제가 발생할 수 있다. 특히, 유저의 포인트와 같이 금전적 데이터를 다루는 경우 정합성이 중요하므로 Read Through / Write Through 전략을 적용 하였다. 하지만 이러한 전략에도 DB 장애 발생 시 캐시 데이터와 불일치 문제가 생길 수 있다. 이를 방지하기 위해 DB 우선 요청을 통하여 DB 작업을 먼저 수행하고, 성공 여부에 따라 캐시를 업데이트하거나 롤백한다. (장애 상황을 대비하여 Cache를 일시적 저장소로만 이용하고 주요 데이터의 정합성을 DB 중심으로 유지)

 

예치금 관련 시나리오

 

 

 

4. 동시성 문제 처리

실시간 경매 특성상, 짧은 시간내에 많은 요청이 발생하고 동시에 입찰 요청이 발생할 수 있다. 이 경우, DB 의 부하를 줄이기 위하여 입찰(Bid) 정보를 Redis에 Cache 처리하여 유효성을 검증할 경우 동시성 문제가 발생한다. 이를 해결하기 위해 Redisson 의존성을 사용하여 Redis에 분산락을 적용하였다. 

 정상적인 입찰(Bid)이 된 경우 Bid Log 정보를 DB에 별도로 저장하였고 Transaction 처리를 하여서 데이터를 일치시켰다. 만약 DB에 장애가 발생하여 실패하는 경우에는 Cache 내 Bid 정보가 업데이트 되지 않으므로 동일하게 유지할 수 있다.  

 

 

서로 다른 입찰 요청 5건 동시에 발생시 처리 과정

 

 

 

5. Schedular 와 Batch를 이용한 경매 입찰 완료 처리

 

  실시간 경매가 끝나자 마자 입찰 완료 처리

 

  서버에서 짧은 시간 Term을 두고 끝난 경매를 체크 해야한다. 이 때 DB를 조회하여 끝난 경매를 체크 해야 하며 유저의 Point도 원 상태로 복귀 해야한다. 매 시간마다 체크를 해야 하므로 DB에 요청 수가 많아 지므로 병목 현상이 발생할 수 있다.

매 시각 체크를 통하여 경매 종료 처리

 

 

  경매를 등록할 때, Evnet에 경매 종료를 등록하여 입찰 완료 처리

 

  경매를 시작할 때, Event에 등록하여 경매 개별 처리를 할 수 있다. 이 경우, 매번 DB를 조회하지 않아도 되지만 여전히 경매 1건당 예치금을 넣은 기록을 확인하여서 취소 처리를 해야하며 유저의 Point도 원 상태로 복귀 해야한다. 매 건마다 해당하는 작업을 할 경우 DB에 요청 수가 많아 지므로 병목 현상이 발생할 수 있다.

 

경매 Event를 이용하여 경매 종료 처리

 

 

  다음날 00시 기준으로 Scehdular와 Batch를 이용하여 입찰 완료 처리

 

 위의 두가지 문제를 방지하기이를 방지하기 위해 Schedular를 사용하여 다음날 00시에 끝난 모든 경매에 대하여 한번에 Batch 처리를 하여 Data를 Update 하였다. 사용자의 사용이 적은 시간 대를 이용하여 Batch 처리를 하였지만, 그럼에도 불구하고 Batch 처리는 Server 에 부하를 일으킬 수 있으므로 추후에는 별도로 분리하여 처리하도록 리펙토링이 필요하다.

 

Schedular 와 Batch를 이용한 경매 종료 처리

 

 

 

6 테스트 코드를 통한 확인

 Given When Then 형식을 유지하면서 Junit 으로 Test 를 진행하였다. 주로 확인한 사항은 에러나 장애가 발생시 데이터의 정합성을 유지하는지, 예상한 예외와 Transaction 처리가 되었는지를 위주로 Test 하였다.

 

 

예치금 입력 Test

 

 

같은 가격 동시 입찰

 

 

7. 회고

 

 이번 프로젝트를 통하여 서버가 분리된 상태에서 정합성을 유지하는 방법과 예외처리 방법에 대해서 많이 배웠다. 특히 Trasaction 처리와 Cache 에 대하여 많은 것을 생각 해 볼 수 있었고, 서비스가 많아짐에 따라 부하를 줄이기 위해 해당 부분을 분리해야 함을 알게 되었다. 그러므로 추후, Monolithic MSA 전환 프로젝트를 진행하여 DB 중심에서 Cloud 환경 중심의 개발에 대해서도 경험해 볼 예정이다.

 

Monolithic

 

Micro Service Architecture