🎯 테이블 고민했던 점
Game 테이블은 특정 방에서 진행된 한번의 퀴즈 게임을 의미한다.
Game 테이블을 통해서 추후에 퀴즈 시작시간, 종료 시간, 참여자, 풀이한 문제목록 등의 정보 조회가 필요할 것이라고 판단되었다.
그렇다면 Game 테이블이 진행한 게임의 Quiz ID 목록을 가지고 있어야할까?
이 부분은 중간에 game_quiz 테이블을 두어서 특정 게임에 어떤 quiz가 사용되었는지 중간 맵핑 테이블을 두기로 하였다.
(game 테이블과 quiz 테이블이 다대다 관계이기 때문)
마찬가지로 game과 member 간에 다대다 관계를 가질 수 있기 때문에, member_game_result라는 중간 테이블을 두었는데, 이 테이블은 특정 방의 게임 중에서도 특정 회원의 구체적인 게임 결과를 기록하는 테이블로 두었다.
게임 전체에 대한 대략적인 정보는 game 테이블에, 특정 플레이어의 구체적인 게임 결과 정보는 member_game_result 테이블에 두기로 하였다.
마지막으로 플레어가 퀴즈 방 입장 시간과 퇴장 시간을 어떻게 기록해줄지 고민되었다.
플레이어는 1개의 방에 대해 들어갔다 나올 수 있고, 추후에 또다시 들어갔다 나올 수 있다.
즉, 같은 방에 여러번 들어왔다 나갔다 할 수 있다는 것이다.
위와 같은 상황이라면 room_id와 member_id를 1:1로 매칭시킬 수 는 없다. 왜냐하면 같은방에 같은 회원 데이터가 여러개 있을 수 있기 때문에 중복될 수 가 있다.
그래서 고민한 결과로 플레이어가 방에 참여간 참여 기록만을 기록하기로 하였다.
이유는 플레이어가 나간 시간을 별도로 기록할 필요까지는 없을 것이라고 판단되었다.(요구사항에 필요하지 않았고, 복잡성을 줄일 수 있음)
플레이어가 특정 방에 참여한 시간을 기록하고, room 테이블에서 현재 방 인원수 변경 정보를 철저하게 기록해주기로 하였다.
이렇게 되면 room테이블의 현재 방 참가 인원수(curr_capacity)가 3이라고 했을 때, 가장 마지막에 참여한 3명의 정보를 room_join테이블에서 조회해오면 현재 room에 참여중인 플레이어가 목록을 조회해올 수 있다.
위와 같은 방식을 했을때에 주의사항은 room 테이블 안의 curr_capacity와 max_capacity의 변경에 대해 동시성 문제를 확실하게 고려를 해야한다. (이유는 당연히 회원들의 방 참여자 정보가 room테이블의 curr_capacity에 의존하기 때문.)
최종적으로 설계해본 테이블은 아래와 같다.
🎯 아키텍처 고민했던 점
현재 기획한 내용은 아래와 같다.
1. 회원, 게임, 퀴즈, 게임방 API 개발
2. Stomp를 활용한 실시간성/양방향 퀴즈게임 개발
위의 정보를 토대로 대략적인 설계를 아래와 같이 해보았다.
서버는 크게 아래와 같이 2개의 서비스가 존재한다.(현재는 최대한 간단하게 단일 서버(모듈) 형식으로 구성합니다..! )
1. REST API를 담당할 Core API 서비스가 존재한다.(회원, 게임, 퀴즈, 게임방 도메인)
2. 퀴즈/정답 정보를 실시간으로 주고받을 실시간 퀴즈 서비스가 존재한다.
여기서 Core API 서비스에 게임 시작 요청(ex. POST /v1/game)과 같은 요청이 들어오면 별도로 게임 퀴즈 문제들을 프론트 엔드에 시켜줄 스레드가 필요하다고 생각되었다. (게임 시작 HTTP 요청은 게임이 시작되었다는 응답과 함께 바로 반환되어야 하기 때문)
그래서 아래와 같이 퀴즈문제를 실시간으로 프론트엔드에 전송(push?)시켜줄 비동기 스레드를 동작시키기로 하였다.
\
게임 시작 API 요청이 들어오면, 게임 진행 관련한 동작은 별도의 스레드에게 위임 한다.
게임 진행 서비스는 이제 Stomp Service라는 실시간 연결 서비스를 통해서 특정 방에 참여중인 클라이언트(사용자)들에게 퀴즈를 전달해준다.
그러면 사용자들은 퀴즈에 대한 정답정보를 Stomp Service에 전송하고 해당 데이터를 게임 진행 서비스에게 전달해줘서 누가 선착순으로 맞췄는지 계산하고, 결과를 실시간으로 반환한다.
여기서 여러 사용자들로부터 들어오는 정보를 선착순으로 받기 위하여 Queue 자료구조를 사용하면 좋겠다고 생각했다.
이를 위해서 여러가지 선택지가 있었는데 아래와 같다.
1. 로컬 환경의 Queue 자료구조
2. Redis를 활용한 List(Queue) 자료구조
3. Redis Streams
4. 기타 외부 메세지 브로커(ex Rabbit MQ)
비록 초기 단계로 단일서버이긴 하지만, 서버 확장성을 고려한다면 로컬보다는 외부 서비스를 사용하는게 좋을 것 같다고 생각했다.
그리고 조금 작은 단위로 빠르게 배포/개발과 key-value형식으로 특정 방에서 들어오는 메세지 정보를 유용하게 구별할 수 있다는 점 등을 판단해서 Redis 자료구조를 활용하기로 하였다.(List를 사용해서 구현해볼 예정..! Stream는 여러 소비자가 있을 때 더 효율적일 것으로 보임)
(Redis List로 일단 구현은 했지만.. 추후에 엄청 비효율적인 코드가 발생하게 되는데..)
'프로젝트 > CStar' 카테고리의 다른 글
[프로젝트] Redis 를 Queue로 활용했을때 성능 & 동시성 체크해보자 (0) | 2024.09.04 |
---|---|
[프로젝트] Busy Waiting 어떻게 개선해볼 수 있을까? (0) | 2024.09.02 |
[프로젝트] 테스트와 배포 자동화 (1) | 2024.09.01 |
[프로젝트] 이슈 & PR 템플릿 (1) | 2024.09.01 |
[프로젝트] 프로젝트 기획하기(CStar 퀴즈 웹 애플리케이션) (0) | 2024.08.17 |