프로젝트/프로젝트 회고

[최종 프로젝트 - 현재 시세를 반영한 모의 투자 서비스] 주문 도메인 성능 개선(Redisson 분산락 적용)

코딩로봇 2025. 6. 18. 14:00

이번 프로젝트에서 모의 투자 서비스의 핵심 기능인 "주문 체결"에 대해 맡았다.

실시간 시세를 기반으로 여러 사용자가 동시에 시장가 매수를 시도할 경우, 잔고 차감 및 보유 종목 업데이트가 정확히 반영되지 않으면 데이터 정합성 문제가 발생한다.

이 문제를 해결하기 위해, Redisson 기반의 분산락을 커스텀 어노테이션 방식으로 도입하였다. 

 

 

TradeService에 Redisson 락 적용하기

📌 문제 상황

  • 다수의 유저가 동시에 동일한 계좌로 매수 주문을 보낼 경우, 잔고 차감보유 종목 수량 증가가 동시성 문제가 발생하면서 데이터가 꼬여버렸다.

 

동시성 제어에 대해 이론적으로 다룬 글이 있어 해당 글을 참고하였다.

https://computerreport.tistory.com/154

 

[Spring]동시성 제어(Redisson)

5분 브리핑을 진행하면서 다수의 멀티 스레드로 동시 주문을 실행하면 데이터 정합성 문제가 발생하는 것을 다루었고 본격적으로 성능 개선을 위해 분산 락을 적용해볼려고한다.✅분산 환경에

computerreport.tistory.com

 

📌 해결 방법

  • Redisson을 활용한 분산락을 커스텀 어노테이션으로 구성하였다.
  • 또한 트랜잭션을 락 내부에 배치하여 커밋 후 락 해제되도록 구성하였다
@Around("@annotation(distributedLock)")
public Object lock(ProceedingJoinPoint joinPoint, DistributedLock distributedLock) throws Throwable {
    RLock lock = redissonClient.getLock(distributedLock.key());
    boolean isLocked = lock.tryLock(...);
    try {
        return transactionTemplate.execute(status -> joinPoint.proceed());
    } finally {
        if (isLocked && lock.isHeldByCurrentThread()) lock.unlock();
    }
}

 

 

그럼 주문 저장에도 락이 필요할까?

"주문 체결은 락이 필수지만, 그 이전 단계인 '주문 저장'에는 락이 꼭 필요할까?" 라는 생각이 들었다.

 

📌 전제 조건

  • 주문 저장 로직은 각 사용자의 고유한 계좌를 대상으로 처리된다.
  • 주식 종목에 대한 수량 한도 제한이 없으며, 동일 종목에 대한 중복 주문도 가능하다.
  • 주문 저장 단계에서는 단순히 DB에 주문 정보를 넣는 수준의 처리만 존재한다.

 

결론적으로 굳이 락을 걸 필요 없다.

 

 

이유는 체결은 공유자원을 변경하므로 락이 필요하지만 주문 저장은 개별 자원에 대한 독립 처리이므로 락이 없어도 정합성 유지가 가능하다. 또한 불필요한 락 처리는 성능 속도를 저하 시킬 수 있다.

 

 

 

사용자 요청 중복 이슈는 어떻게 처리해야 할까?

근데 디테일 하게 들어가면 또 다른 상황을 생각 해보아야한다.

웹 환경에서는 사용자 인터페이스(UI)나 네트워크 지연으로 인해 같은 주문 요청이 중복해서 서버로 전송될 수 있다.

예를 들어,

 

  • 사용자가 버튼을 한 번 클릭했지만, 브라우저에서 두 번 요청을 보내는 경우 (더블 클릭, UI 지연)
  • 네트워크 재전송으로 동일 요청이 반복될 가능성

 

이 경우에도 락을 걸어야 할까?

중복 요청 방지는 락보다 “중복 요청 방지 로직”으로 해결하는 것이 바람직하다.

  • 락은 자원 보호용이며, 같은 요청이 여러 번 오는 걸 감지하거나 방지하는 목적은 아니다.
  • 이것은 분산락의 책임 영역이 아니라, API 요청의 무결성 보장 책임에 가까운 것이다.

이 문제를 해결할려면 Redis에 3~5초 정도 저장해두고, 같은 내용이 오면 무시하는 방식을 생각 해봐야한다.

다음글은 Redis 캐싱을 이용한 성능개선을 다뤄보려고 한다.