게임 서비스의 대기열 시스템 구현하기
대기열 시스템이란?
유명한 게임을 해본 사람이라면 한번쯤은 대기열을 기다리느랴 순번을 받고 대기해 본 경험이 있을 것이다.
대기열 시스템이란 갑작스런 접속자 폭증 등으로 장애가 발생하는 것을 방지하고 안정적인 서비스를 위해 서버에 접근하는 인원을 제한하기 위한 시스템을 말한다. 꼭 유명하고 트래픽이 많지 않더라도 운영상의 이유로 서버자원이 적게 할당되어 있어 대기열을 두는 경우도 있기도 하다.
대기열 시스템 유무에 따른 차이
대기열 시스템이 없는 경우
트래픽이나 사용자가 얼마 없는 서비스의 경우 대기열 시스템이 없어도 크게 상관은 없지만 다수의 동시접근이 발생할 경우 접속 장애가 발생할 수 있다. 다음과 같이 다수의 유저가 서비스를 접근한다고 생각해보자.
서비스 서버의 수용인원이 100명일 때, 200명이 접근할 경우 100명은 접속 장애를 겪게 된다. 심하게는 서버 장애 발생으로 이미 접속한 100명의 사용자들도 장애를 겪어 서비스 자체가 마비될 수도 있다.
대기열 시스템이 있는 경우
대기열 시스템이 구현되는 방식은 매우 다양하고 자유로운데 보통 순차처리를 하는 자료구조인 Queue를 구현한 시스템으로 만들어 놓는 경우가 많다.
서버 접속 전 단계에 순차접근 대기열 시스템을 구현하면, 100명을 수용하는 서버에서 101명 부터는 접속 대기 상태가 되며 유저가 접속을 종료할 때마다 차례대로 접근할 수 있도록 하여 장애를 방지할 수 있다.
처리 프로세스
이론적으론 간단하게 생각 할 수 있는데 어떤 식으로 구현하면 좋을 지 생각해보자.
우선 다음과 같이 주체를 정의 해보겠다.
유저(클라이언트) | A |
대기열서버 | B |
게임서버 | C |
A. 클라이언트
게임을 이용하는 실질적인 사용자로 다음과 같은 행위를 처리한다.
- B로부터 입장 순번 발급 및 입장 가능 여부 폴링
B. 대기열 서버(캐시류 스토리지)
우리가 구현하려고 하는 대기열 시스템으로 주로 Redis 같은 저장소를 사용한다. 중소규모 서비스는 RDB를 사용하기도 하지만 멀티쓰레드에서의 상태 업데이트 관리를 신경써야 하는 부분이 있다. Redis의 경우 싱글스레드로 이 문제에서는 자유로운 장점이 있다. 시스템 역할로는 다음과 같이 두가지 상태를 관리한다.
- 입장 가능한 순번 상태 관리
- 발급한 순번 상태 관리
- C로부터 받은 입장 가능한 순번 업데이트
C. 게임 서버
유저의 접근 대상이 되는 게임 서버로 다음 역할을 수행한다.
- 입장권 검증 및 A의 입장 처리
- 동접자 체크를 통한 B에 입장 가능한 순번의 갱신 요청 (ex. +200명 가능이요~)
상세 프로세스
-
A가 B에게 순번을 받는다.
-
B는 저장된 발급순번을
1
증가시킨다. (INCR) -
A는 주기적으로 B에 폴링하여 가진 순번이 입장 가능한 순번인지 확인한다.
-
여기서 B는 입장가능한순번 및 발급순번을 가지고 있기 때문에 요청한 순번이 입장가능한지 확인할 수 있다.
(입장 가능한 순번의 초기 값은 최초 서버수용 가능 인원으로 설정) -
A의 발급순번이 B의 입장가능한순번 이하일 때 입장권을 주고 C에 접근을 허락한다.
-
입장 가능한 순번의 갱신은 C의 동접에 따라 C가 B에게 순번 증가를 요청해준다.
(마지막 입장순번을 기억해서 순번 자체를 올리거나, 서버수용가능 n만큼 올리도록 요청할 수 있다.) -
일련의 과정이 반복된다.
생각하기
대기열 서버도 서버이므로 장애가 발생할 여지가 있다. 대기열 서버 상태가 좋지 않으면 대기열 서버를 거치지 않더라도 서버에 접근할 수 있는 등의 대체 접속 방안 마련이 필요하다. 또한 실제 라이브 서비스에서는 안정적인 서비스 제공을 위해 ElastiCache같은 서비스를 고려하는 것이 좋다.
가능하다면 서버쪽에서 입장권에 대한 검증이 있어야 할 것이다. 그리고 수용가능한 인원 갱신 또한 너무 적지도 과하지도 않아야 이후의 접근 허용 시 서버에 부담이 가지 않을 것이다.