Blog

[Spring][258] Spring 세마포어를 통한 동시성 오류 해결

Category
Author
Tags
PinOnMain
1 more property

세마포어란?

세마포어는 다중 스레드 프로그래밍에서 동시에 공유 자원에 접근하는 스레드의 수를 제한하여 동시성 문제를 방지하는 데 사용되는 변수나 추상 데이터 타입입니다.
세마포어는 특정한 수의 토큰을 가지며, 스레드가 세마포어를 획득하려면 토큰을 얻어야 합니다. 토큰이 없다면, 스레드는 대기 상태에 들어갑니다.
세마포어는 주로 두 가지 종류가 있습니다
이진 세마포어카운팅 세마포어이진 세마포어는 0 또는 1의 값을 가지며, 상호 배제를 위해 사용됩니다.
카운팅 세마포어는 0 이상의 값을 가질 수 있으며, 제한된 수의 자원에 대한 접근을 관리합니다.
현제 이 글에서 동시성 문제 해결을 위해서 이진 세마포어를 사용했습니다.

문제 상황

이벤트 신청 페이지

현재 프로젝트를 진행하며 이벤트 신청 페이지를 통해 사용자들이 책을 신청할 수 있는 기능을 제공하고 있습니다.
그러나 성능 테스트를 해보니 다수의 사용자가 동시에 같은 책을 신청할 때 문제가 발생하였습니다.

JMeter을 이용한 동시성 테스트

문제를 파악하기 위해 JMeter를 사용하여 동시성 테스트를 진행하였습니다.
여러 사용자가 동시에 같은 책을 신청하는 시나리오를 설정하여 테스트를 진행한 결과, 하나의 책에 대해 여러 개의 신청이 접수되는 현상을 확인할 수 있었습니다.
이러한 현상은 동시성 오류로 인해 발생하는 것으로 하나의 책은 오직 한 사람에게만 기부될 수 있어야 하지만 여러 사람에게 기부가 되는 것처럼 잘못 처리되었습니다.
이는 서비스의 신뢰성을 해치는 심각한 문제로 즉각적인 해결이 필요했습니다.

해결 과정

세마포어를 이용한 동시성 해결

우선 세마포어를 사용하여 동시성 문제를 해결하기로 결정하였습니다. 세마포어는 동시에 접근할 수 있는 스레드의 수를 제한하여, 한 번에 하나의 스레드만이 공유 자원에 접근할 수 있도록 하는 동기화 메커니즘입니다.
1.
세마포어 설정
@Configuration public class SemaphoreConfig { @Bean public Semaphore binarySemaphore() { return new Semaphore(1, true); } }
Java
복사
1.
세마 포어 반영
private final Semaphore semaphore; @PostMapping("/bookApplyDonation") public ResponseEntity<MessageDto> createBookApplyDonation(@RequestBody BookApplyDonationRequestDto bookApplyDonationRequestDto){ try{ semaphore.acquire(); return ResponseEntity.ok().body(bookApplyDonationService.createBookApplyDonation(bookApplyDonationRequestDto)); }catch (InterruptedException e) { e.printStackTrace(); return ResponseEntity.badRequest().body(new MessageDto("나눔 신청에 실패했습니다.")); }finally { semaphore.release(); } }
Java
복사
실제 이벤트 신청 로직에 세마포어를 적용하였습니다.
1.
결과 확인
세마포어 적용 후 다시 동시성 테스트를 진행한 결과, 이번에는 모든 사용자가 동일한 책을 신청하였을 때 오직 한 명만이 신청에 성공하고 나머지는 실패하는 것을 확인할 수 있었습니다.
이를 통해 동시성 문제가 성공적으로 해결되었다는 것을 알 수 있었습니다!!!
1.
성능 테스트
시나리오 100명의 사용자가 회원가입하고 로그인 이 후 나눔 신청 한다고 가정 21번 책을 100명의 사용자가 나눔신청을 한다고 가정하겠다.

결과를 보면 95% ~ 99 % 0.6 ~ 0.85초 정도 걸리는 것을 확인 할 수 있다. 예상보다 너무 느리게 나오는 걸 확인할 수 있다. 하지만 이건 회원가입과 로그인을 진행한 이후라 좀 더 느리게 나온 것일 수도 있다.
현재는 조금 더 시각적으로 보기 쉽게 예외를 발생 시켰기에 성능이 조금 작게 나오는 걸로 추정됩니다.
예외를 DTO를 리턴 하는 것으로 바꿔보겠습니다.
시나리오 로그인만 하고 바로 조회 한다면?
테스트 결과 0.5~ 0.7초 사이가 나오는 것을 확인 할 수 있습니다.
시나리오 세마포어를 적용 안했을때는 ?
0.3 ~ 0.7 초 사이가 나오는 것을 알 수 있습니다.
즉 성능 테스트 결과 세마포어를 사용하면 동시성 문제를 해결할 순 있지만 약간의 성능이 저하 된다는 것을 알 수 있습니다.