Skip to content

feat: Redis RBlockingQueue 도입 및 동시성 순서 보장 #156#158

Merged
capDoYeonLee merged 1 commit into
devfrom
feat-RedisQueue-156
Aug 4, 2025
Merged

feat: Redis RBlockingQueue 도입 및 동시성 순서 보장 #156#158
capDoYeonLee merged 1 commit into
devfrom
feat-RedisQueue-156

Conversation

@capDoYeonLee

@capDoYeonLee capDoYeonLee commented Aug 4, 2025

Copy link
Copy Markdown
Contributor
첫 번째 문제 상황 콘솔 image

[첫 번째 문제]
현재 여러 명의 유저가 동시에 정답을 입력할 경우, 서버 내부에서 정확한 우승자를 판별하지 못하는 동시성 문제가 발생하고 있습니다. 예를 들어, 'A' 유저가 먼저 정답을 입력했음에도 불구하고, 나중에 입력한 'B' 유저가 우승자로 처리되는 상황이 발생합니다.

[첫 번째 문제 해결]
이 문제를 해결하기 위해, 서버와 데이터베이스 중 어디에 락을 적용할지 고민해 보았습니다. 게임은 실시간 진행이 중요한 특성이 있기 때문에, 상대적으로 느린 데이터베이스보다는 서버 측에서 낙관적 락을 활용해 동시성을 제어하고자 했습니다.

이에 따라 특정 엔티티에 @Version 어노테이션을 추가하여, 엔티티 수정 시 버전을 검사하는 방식으로 낙관적 락을 구현해 race condition을 해결하고자 했습니다.

[두 번째 문제]
하지만 또 다른 문제가 발생했습니다. 'A'와 'B' 요청이 거의 동시에 들어왔을 때, 요구사항은 먼저 도착한 'A' 요청을 커밋하고, 'B' 요청은 낙관적 락 예외를 발생시켜 롤백되도록 하는 것입니다.

그러나 서버 내부에서는 정확한 요청 순서를 보장할 수 없고, context switching 영향으로 인해 'B' 요청이 먼저 커밋되고, 'A' 요청이 나중에 예외로 롤백되는 현상이 발생하는 상황입니다. 결국 낙관적 락만으로는 이 문제를 완벽하게 해결할 수 없습니다.

[두 번째 문제 해결을 위한 고민한 점]
이러한 문제를 인식하고, 이제는 요청의 순서를 명확히 보장하기 위해 분산락을 적용하는 방식을 도입했습니다. 현재 사용자 'A'와 'B'의 동시에 요청이 들어왔을 때, 분산락을 통해 특정 메서드에서 요청의 순서를 락을 통해 보장해 주며, 'A'가 먼저 커밋된 후 'B'의 요청은 무시가 되거나 이전과 동일하게 @Version 낙관적 락을 통해 이중 체크를 진행하여 race condition을 해결하고자 했습니다.

[세 번째 문제]
Redis를 활용한 분산락을 도입했음에도 불구하고, 여전히 순서를 명확히 보장해 주지 못하는 상황이 발생했습니다. 분산락은 상호배타성만 보장하고, 순서(공정성)까지는 보장해 주지 않는다는 특징 때문에 동시성이 명확히 해결되지 않았습니다. 상황은 아래와 같습니다.

'A'와 'B' 요청이 거의 동시(하지만 정확하게 구분지어 보자면 'A'가 빠름)에 들어왔지만, 분산락을 점유하는 순간까지도 스레드 스케줄링 등 비결정적인 요소로 인해 순서를 완전히 보장하여, 'A'가 더 빨리 들어왔지만, 'B'가 먼저 락을 획득 후 'B'가 먼저 커밋되어 'A' 요청은 낙관적 락 예외로 롤백이 되는 상황에 마주했습니다.

세 번째 문제 예외 로그
Request processing failed: org.springframework.orm.ObjectOptimisticLockingFailureException:
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)

[세 번째 문제 해결을 위한 고민 및 문제 해결]
이러한 문제의 근본 원인을 명확히 파악하고, 요청의 순서를 완벽히 보장할 수 있는 비즈니스 로직의 필요성을 느꼈습니다. 이를 위해 Redis Queue를 도입하여 각 요청에 타임스탬프를 추가한 뒤, 이를 Redis Queue에 저장하고 비동기적으로 큐에서 작업을 처리하여 최종 게임 결과를 반환하는 방식과 함께 낙관적 락 기법을 통해 이중 체크로 동시성 문제를 해결할 수 있었습니다.

@capDoYeonLee capDoYeonLee merged commit e89ba05 into dev Aug 4, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant