본문 바로가기
📕 Spring Framework/Spring Project

2022.06.02 「DB 동시성 문제」

by GroovyArea 2022. 6. 2.
자바 기반 웹 프로그램은 기본적으로 멀티스레딩을 기반으로 하기 때문에, 동시성 관련 문제를 잘 해결해야 한다고 들었다. 
이번에 내가 하는 쇼핑몰 프로젝트에서도 그 이슈가 딱 터졌다. 
예를 들어 몇 만 명이 한정된 재고의 상품을 주문하려고 할 때?
수많은 멀티스레드는 데이터의 재고량을 조회하며 재고가 떨어졌으면 예외를 발생시키면 된다.
하지만 동시에 접근하면? 이거 난감하다. 이 문제에 대한 고찰을 작성하겠다.

 

DB 동시성 문제

동시에 DB를 조회할 때가 문제이다.

 

내가 사용하는 DBMS는 Mysql

Mysql은 기본적으로 트랜잭션의 격리 수준으로 Level 2 Repeatable Read를 사용하고 있다. 언두 영역을 통한 다양한 버전 별 MVCC를 통해 버전에 맞는 값을 조회할 수 있다. 

 

하지만 모든 기술은 문제가 있기 마련이다.

그것은 바로 Phantom Read이다.

=> 한 트랜잭션 내에서 같은 쿼리를 두 번 수행할 경우, 첫 번째 쿼리에서 없던 유령 레코드가 두 번째 쿼리에서 나타나는 현상

 

참조 : https://itpenote.tistory.com/616

 

Phantom Read

I. Phantom Read 정의 한 트랜잭션 내에서 같은 쿼리를 두 번 수행 시, 첫 번째 쿼리에서 없던 레코드(유령, Phantom)가 두 번째 쿼리에서 발생하는 현상 절차 절차 트랜잭션 데이터 예제 설명 ① Read Tra

itpenote.tistory.com

 

내 프로젝트에서의 DB 동시성 문제

 

조건 

=> 수 만명의 사람이 한정된 재고의 상품을 구매하려고 한다. 이때 동시에 주문 버튼을 눌렀을 때 어떻게 해야 할까? (팬텀 리드 발생)

 

절차

재고는 믿을 수 없는 값이 된다.

 

해결법

데이터 베이스의 락을 이용하자

=> 재고를 확인하는 순간 리소스를 점유하는 것이다. Mysql은 기본적으로 레코드 락이므로, 해당 레코드의 트랜잭션 동안 락을 점유하는 것이다.

 

쿼리를 통해 락 점유

=> For Update를 통해 트랜잭션 수행동안 락을 획득해 멀티 스레드 환경에서도 리소스를 점유한다.

 

@Transactional
public String getkakaoPayUrl(OrderDTO orderDTO, HttpServletRequest request) throws RunOutOfStockException {

    /* 재고 확인 */
    int productStock = productMapper.selectStockOfProduct(orderDTO.getItemName());
    if (orderDTO.getQuantity() > productStock) {
        throw new RunOutOfStockException("해당 상품이 품절되었습니다.");
    }

서비스 레이어에서 트랜잭션을 건다. 

/* 재고 차감 */
updateStock(productStock - orderDTO.getQuantity(), orderDTO.getItemName(), "product_name");

같은 메서드 내의 또 다른 update 쿼리 => 예외가 발생하면 전부 롤백이 되어야 한다. 트랜잭션의 원자성!

 

장바구니를 결제해보자

기존 상품 재고량은 120개 씩이다.

 

성공할 경우

=> 두 번 결제했으므로 제대로 수량 차감이 되는 것을 볼 수 있다.

 

하지만 락을 건다는 것은 성능의 문제가 생긴다는 것이기 때문에, 각별히 신경 써서 주의하며 사용해야 될 것 같다.

 

성능을 고려한 리팩토링!! (추가)

다음 글을 읽어보세요 ㅎㅎ

 

동시성 조회 문제 해결 및 성능에 관한 고민 [Lock, Queue, Redis]

주문 건에 대한 상품 재고 파악 동시성 관련 이슈에 대해 고민한 하루다. 프로젝트 리팩토링을 시작하며 지난 도메인들은 기본 crud API만을 다루었다. 5일동안 JPA 강의들을 수강하며 본격적으로

sweeeetgoguma.tistory.com

 

반응형