티스토리 뷰

동시성(Concurrency)

동시성은 단일 코어에서 시간 분할을 통해 여러 스레드를 번갈아 수행하여 동시에 작업이 처리되는 것처럼 보이게 만드는 개념이다. I/O 작업(사용자 입력, 네트워크 요청, 파일 입출력 등) 중 CPU가 유휴 상태일 때 context switching으로 다른 스레드 작업을 처리하여 효율성을 높일 수 있다. 이를 통해 서버는 여러 클라이언트 요청을 동시에 처리할 수 있지만, 동시성 환경에서는 Deadlock, Race Condition, Starvation 등의 문제가 발생할 수 있어 신중한 설계가 필요하다.

비관적 락

특징: 다른 트랜잭션이 해당 데이터에 접근하려고 하면 락이 해제될 때까지 기다리게 한다.

장점: 데이터 충돌을 방지하여 트랜잭션이 실패할 위험이 적고 데이터의 일관성과 무결성을 보장한다.

단점: 경쟁이 치열한 경우 성능이 저하되고 데드락 발생 가능성이 높아질 수 있다.

낙관적 락

특징: 버전 관리 또는 타임스탬프를 사용하여 충돌 여부를 체크한다.

장점: 데이터 접근에 대한 제한이 없고 병렬 처리를 최대로 활용할 수 있다.

단점: 트랜잭션 충돌이 발생하면 롤백되고 재시도도 가능하지만 충돌이 빈번할 경우 성능 저하로 이어질 수 있다.

 

※ 병렬 처리

여러 작업이나 트랜잭션이 동시에 수행될 수 있도록 하는 처리 방식입니다. DB에서 병렬처리는 여러 사용자가 동일한 자원(데이터) 접근하거나 작업을 수행할 때, 시스템이 이를 효율적으로 관리하여 동시에 처리할 수 있도록 지원하는 것을 의미합니다.


1. 좌석 선점(예약)

최대 50명의 사용자가 동시에 동일한 좌석에 예약을 할 경우 발생.

락 적용 방식

1. 낙관적 락

  • Version 필드를 통해 버전 번호를 관리
  • findByConcertIdAndConcertScheduleIdAndConcertSeatIdIn 메서드에 @Lock(LockModeType.OPTIMISTIC)을 적용하여 좌석 정보 조회 시 낙관적 락을 사용
  • 동일 좌석에 대한 동시 예약 시, 한 사용자가 업데이트를 완료하면 다른 사용자의 트랜잭션에서 OptimisticLockException이 발생
  • 해당 시나리오에서는 재시도가 필요하지 않아 구현하지 않았습니다.

2. 비관적 락

  • findByConcertIdAndConcertScheduleIdAndConcertSeatIdIn 메서드에 @Lock(LockModeType.PESSIMISTIC_WRITE)를 적용하여, 좌석 정보를 조회할 때 비관적 락이 적용되도록 변경
  • 그 결과 데이터를 조회 및 수정하는 동안 다른 트랜잭션이 해당 데이터에 접근하려고 하면 대기

수행 시간( 총 실행 횟수: 10)

  낙관적 락 (50명) 비관적 락 (50명) 낙관적 락 (1000명) 비관적 락 (1000명)
전체 평균 소요 시간 461ms 542ms 1sec288ms 1sec481ms
최소 소요 시간 155ms 171ms 980ms 1094ms
최대 소요 시간 162ms 231ms 1018ms 1280ms
평균 소요 시간 158ms 194ms 996ms 1113ms

결론

좌석 선점 시나리오에서는 많은 사용자가 동시에 접근할 가능성이 높음에도 불구하고 낙관적 락이 적합하다고 생각합니다. 낙관적 락은 충돌이 적고 동시에 접근이 많지 않은 상황에서 사용되는 것이 일반적이지만, 좌석 선점의 경우에도 적합한 이유는 재시도 처리가 필요하지 않기 때문입니다. 

 

좌석 선점 시 충돌이 발생하면 예외를 발생시킨 뒤, 다른 좌석을 선택하도록 유도하는 방식으로 처리하면 되므로 재시도로 인한 성능 저하가 발생하지 않습니다. 이는 낙관적 락의 단점 중 하나인 재시도 비용을 상쇄시키며, 빠른 시간 내에 많은 사용자가 좌석을 예약할 수 있도록 효율적으로 동작할 수 있게 합니다.

 

반면 비관적 락은 대기 시간이 증가하기 쉽고, 트랜잭션이 길어질수록 병목 현상이 발생해 사용자 경험을 저하시킬 가능성이 큽니다. 따라서 좌석 선점처럼 동시에 많은 사용자가 접근하지만 빠른 응답성과 효율적인 처리가 중요한 시나리오에서는 낙관적 락이 더 적합하다고 판단됩니다.

 

결론적으로, 좌석 선점 시나리오에서 낙관적 락을 사용하는 가장 큰 이유는 재시도 처리가 필요 없고 빠른 응답성을 유지할 수 있기 때문입니다.


2.  잔액 충전

동일한 사용자가 동시에 5번 충전했을 때 5번 다 충전이 되어야 한다.

락 적용 방식

1. 낙관적 락

  • @Version 필드로 통해 버전 번호를 관리하고 findByUserId 메서드에 @Lock(LockModeType.OPTIMISTIC) 적용했습니다.
  • 해당 시나리오에는 retry이가 필요해서 리트라이 횟수를 1000번으로 설정해 구현했습니다.
  • retry 설정을 2번으로 했을 경우 실패하기도 했습니다.

2. 비관적 락

  • findByUserId 메서드에 Lock(LockModeType.PESSIMISTIC_WRITE) 적용하여 잔액을 조회할 때 비관적 락이 적용되도록 했습니다.

수행 시간( 총 실행 횟수:5)

  낙관적 락 (2번) 비관적 락 (2번) 낙관적 락 (5번) 비관적 락 (5번)
전체 평균 소요 시간 564ms 391ms 778ms 425ms
최소 소요 시간 210ms 76ms 348ms 94ms
최대 소요 시간 240ms 92ms 565ms 129ms
평균 소요 시간 222ms 85ms 457ms 108ms

결론

동일 사용자가 동시에 여러 번 잔액을 충전하는 시나리오에서 비관적 락이 더 적합하다고 생각합니다. 낙관적 락은 재시도 횟수 설정에 따라 처리 성능이 크게 달라지며, 재시도가 반복될수록 시간과 자원이 추가로 소모됩니다. 특히 예상치 못한 여러 상황에서 재시도가 자주 발생할 경우, 낙관적 락은 성능 저하가 심할 가능성이 높습니다. 이러한 이유로, 돈과 같이 중요한 데이터를 다룰 때에는 낙관적 락이 효율적이지 않을 수 있습니다.

 

반면, 비관적 락은 초기 접근에서부터 충돌을 방지하기 때문에 재시도를 피할 수 있어 성능이 안정적입니다. 두 락의 성능과 자원 소모에 차이가 있기 때문에, 데이터를 다루는 상황에서 데이터의 중요성과 충돌 가능성을 고려해 락을 선택하는 것이 좋을 거 같습니다.

 

끝.

728x90
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함