-
Notifications
You must be signed in to change notification settings - Fork 3
[feat] gameStart 및 handlePlayerReady 레디스 분산락 기반 동시성 제어 적용 #123
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- gameStart 중 플레이어 준비 상태 변경 방지 - 플레이어 준비 중 gameStart가 읽기 방지
- 락 획득 성공/실패 케이스 테스트 - 인터럽트 예외 처리 테스트 - 락 해제 조건 검증 - 메서드 실행 중 예외 시 락 해제 정상 동작 확인 - SpEL 기반 동적 락 키 생성 검증
- 멀티스레드에서 하나의 스레드만 락 획득 성공하는지 확인 - 단일 스레드 락 획득 정상 동작 테스트 - 서로 다른 키로 락 사용 시 동시 실행 가능 여부 검증 - gameStart와 handlePlayerReady 메서드 간 동일 roomId 락 충돌 테스트 - 테스트용 서비스 클래스 추가
backend/src/main/java/io/f1/backend/global/config/RedissonConfig.java
Outdated
Show resolved
Hide resolved
backend/src/test/java/io/f1/backend/global/config/RedissonTestContainerConfig.java
Outdated
Show resolved
Hide resolved
| timerService.startTimer(room, START_DELAY); | ||
|
|
||
| PlayerListResponse playerListResponse = toPlayerListResponse(room); | ||
| log.info(playerListResponse.toString()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
디버깅용 로그인가요 ㅎㅎ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵 gameStart에 락을 안걸었을 때, gameStart가 플레이어의 레디를 전부 읽고나서, handlePlayerReady가 동작해서 실제로 false인 상태로 게임이 시작되는지 보려고 적어놨었습니다!
지금은 필요없을것 같은데 로그 정리해서 커밋해 놓았습니다!
jiwon1217
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨습니다 !
sehee123
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
멋져요.. 👍
수고하셨습니다!
silver-eunjoo
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
와.. 어려우셨을 텐데 대단하십니다.. ! 확인했습니다. 고생하셨어요!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[L5-참고의견]
테스트 코드에 Order는 어떤 이유에서 넣으신 건가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
서로 테스트간 의존성은 없긴한데 성공, 인터럽트, 실패 순으로 나눠놨습니다!
🛰️ Issue Number
Closes #108
🪐 작업 내용
Redisson 라이브러리 사용
Redisson은 기본적으로 다양한 분산락 구현 기능이 제공되어 해당 라이브러리를 사용해 구현했습니다. 또한, AOP로 분산락을 구현해 여러 서비스의 메서드에 선언적으로 표현할 수 있도록 했습니다. 어노테이션을 사용하는 경우, 코드 중복도 줄고 의도나 가독성에 유리하다고 생각됩니다.
분산락 키 해시태그 사용
lock:room:{roomId}
{}를 붙이면 해시태그 안의 값으로만 해시값을 계산해 노드에 할당하기 때문에,특정 roomId와 관련된 추가적인 키를 생성할 때 확장성을 고려해, 같은 roomId끼리 같은 슬롯에 저장되도록, 해시태그를 붙였습니다.
gameStart와 handlePlayerReady 동시성 문제 해결
gameStart와handlePlayerReady가 동시에 접근할 경우위와 같이
gameStart가 모든 플레이어의 준비상태를 true로 읽고 나서,handlePlayerReady가 실행되어 플레이어의 준비상태가 false가 되어있는 것을 볼 수 있습니다.gameStart와handlePlayerReady가 겹치지 않기 위해서는 모든 플레이어의 상태를 읽는gameStart때문에 roomId에 락을 획득하도록 했습니다. 또한, gameStart에 걸려있는 락과 동일한 락을 사용해야 의미가 있어 handlePlayerReady에도 roomId로 락을 획득하도록 했습니다.gameStart의 경우, 요청 이후에 들어오는handlePlayerReady요청에 대해서는 즉시 실패시키도록 waitTime을 0으로 설정했습니다.락 관련 에러코드 추가 (CommonErrorCode)
위와 같이 락 획득에 실패하는 경우, 락 획득 실패 예외처리를 추가했습니다. 인터럽트 예외의 경우는 Java에서 InterruptedExcetpion로 스레드 관련 예외로 표준화 되어있어 따로 커스텀예외를 추가하지 않았습니다.
📚 Reference
아래는 분산락 구현 시, 참고한 사이트입니다.
https://helloworld.kurly.com/blog/distributed-redisson-lock/#3-분산락을-보다-손쉽게-사용할-수는-없을까
https://redisson.pro/docs/configuration/#single-mode
✅ Check List