- Game Matching API 서버로써, ASP.NET Core 8로 제작되었습니다.
- 매치 메이킹을 담당하는 서버로써, Game API 서버와 Game Socket 서버와 통신을 합니다.
- 멀티 스레드를 사용하고 있으며, 각 스레드의 기능은 다음과 같습니다.
- API 요청 스레드들 : API 요청을 처리하며, 매칭 입장, 퇴장, 체크 등을 처리합니다.
- 매칭 처리 스레드 : 단일 스레드로, 매칭 입장이 된 유저들을 확인하여 게임 서버에게 매칭 처리 시도를 해주는 스레드입니다.
- 매칭 완료 처리 스레드 : 단일 스레드로, 게임 서버로 매칭 처리 시도가 완료된 요청들을 처리하는 스레드입니다.
- Match Worker 코드
| 종류 | 라이브러리 |
|---|---|
| Framework | ASP.NET Core 8 |
| Redis | CloudStructures |
| Logger | ZLogger |
| 기능 | 완료 여부 |
|---|---|
| 매치 입장 | 완료 |
| 매칭 취소 | 완료 |
| 매칭 체크 기능 | 완료 |
- Redis List 기능을 통해 게임 서버와의 통신을 구현하였습니다.
- 매칭의 경우, 여러 게임 서버가 존재한다고 가정하였고, Redis의 List를 Queue처럼 사용하여 제일 먼저 데이터를 가져간 게임 서버가 자신의 주소와 룸 Number를 유저에게 알려주는 방식으로 진행함.
- 레디스에 유저의 현재 상태(로비, 매칭, 게임 등)를 저장하였고, 매칭 요청에 대해서 다음과 같이 처리함.
- 매칭 요청 : 유저가 로비 상태일 경우, 매칭 List에 추가하도록 처리. 이 외에는 실패 처리
- 매칭 취소 : 유저가 매칭 상태일 경우, 매칭 List에서 삭제하도록 처리. 이 외에는 실패 처리
- 각 서버들끼리 직접적인 통신을 안하게 하는 것이 좋다.
- 실제 라이브 중에서 스케일 아웃이나 장애 대응 등에 문제가 없는 방식으로 해야 한다.
- 메시지 큐나, 레디스, 소켓 직접 연결, 또는 요청 응답 -> 소켓서버에세 요청 응답 등 어떻게 할 것인지에 방법이 다양하다.
- 유저가 어느 정도 기다려야 하는지에 따라서 구현 방법이 달라질 수 있다.
- 매칭 서버의 경우 기본적으로 2 + α 의 스레드들이 동작하며 매칭 List에 동시 접근을 하는 상황이 발생
- 따라서 스레드 동기화 문제를 해결해야하며, 해결하는 과정 속에서 성능을 위해 오버헤드가 최소한으로 발생하여야 함.
- 기존의 ConCurrent 자료형의 경우, 다음과 같은 문제가 발생
- ConCurrentBag, ConCurrentQueue, ConCurrentStak : 추가는 가능하나, 특정 유저 정보를 삭제하는 것이 어려움.
- ConCurrentDictionary : 추가 및 삭제에는 용이하나 순회하는 등의 기능을 사용하려면 오버헤드가 많이 발생함.
- ConCurrentList를 따로 만들어서, 추가, 삭제, 첫 번째 데이터 꺼내기에만 Lock을 사용하여 Lock 사용 비용을 최소화할 수 있도록 만듬.
- 유저의 매칭 정보를 게임 서버와 주고 받기 위해서 통신이 필요함.
- 다만, 실장님께서 실제 라이브 중에서 문제가 없는 방식으로 해야 하며, 스케일 아웃이나 장애 대응을 고려해야한다고 말씀해주심.
- 직접 IP를 통해 통신하는 경우 서버가 스케일 아웃을 하거나, 장애 대응이 어렵다고 생각되어, Redis의 Pub/Sub이나 List를 고려.
- Redis의 Pub/Sub의 경우 테스트 해본 결과 다음과 같은 문제가 발생.
- Subscribe한 모든 서버에 데이터가 전송되기에 제일 먼저 받은 게임 서버가 처리하도록 하는 로직과는 다른 방식.
- SubScribe하는 서버가 없다면 데이터가 저장되지 않는 문제.
- 따라서 Redis의 List 방식으로 수정하였고, List를 Queue처럼 사용하여 매칭 로직을 성공적으로 구현할 수 있었음.
