Game Launcher 시스템을 활용한 서버 매핑

위다빈
Cloud Villains
Published in
12 min readJun 5, 2023

과거의 개발 환경

일반적으로 게임 애플리케이션을 개발할 때에는 개발을 위한 Dev 환경, 테스트를 위한 QA 환경, 검증을 위한 Staging 환경, 그리고 서비스 운영을 위한 Live 환경이 필요합니다. 각각의 환경에 맞추어 서버를 배포하기 위해 기존에 많이 사용하던 방식은 환경 별로 나누어 애플리케이션을 빌드하는 것이었습니다. Dev 환경용, QA 환경용, Staging 환경용, Live 환경용으로 개별적으로 빌드하면 애플리케이션은 각 용도에 맞는 환경과 적절하게 통신할 수 있었습니다.

하지만 스마트폰이 보급되고 모바일 게임 산업이 커지면서 상황은 달라졌습니다. 모바일 게임은 플레이스토어, 앱스토어 등의 플랫폼을 통해 배포됩니다. 이러한 플랫폼에 게임을 출시하기 위해서는 플랫폼의 검수 과정을 통과해야 합니다. 검수 과정에서는 애플리케이션이 부적절한 컨텐츠를 포함하고 있지 않은지, 유저의 개인 정보를 동의 없이 수집하고 있지 않은지 등 애플리케이션의 문제 여부에 대해서 체크합니다. 출시하고자 하는 플랫폼에 애플리케이션을 업로드한 뒤, 검수가 완료되어야 게임을 출시할 수 있습니다. 이러한 검수 과정은 짧게는 하루, 길게는 몇 주가 소요되기도 합니다.

Simplified Application Review Process in AppStore
Simplified Application Review Process in AppStore

애플리케이션 검수를 위한 환경

검수 시 애플리케이션은 어떤 환경과 통신해야 할까요? 검수 단계에 들어간 애플리케이션은 출시해야 할 버전이므로 라이브 환경과 통신해야 한다고 생각할 수 있습니다. 하지만 라이브 환경과 통신하게 된다면 현재 게임을 이용중인 플레이어들에게 영향이 없을까요? 데이터베이스 스키마 변경과 같은 업데이트가 있을 경우 라이브 중인 애플리케이션과 검수 중인 애플리케이션은 같은 환경을 이용할 수 없습니다.

이러한 케이스를 극복하기 위해 검수를 위한 별도의 검수용 환경을 만들어 검수 시에만 이용하는 방법이 있습니다. 이 서버에는 검수 이후 출시할 서버와 동일한 환경을 구성해 놓으면 됩니다. 이처럼 검수를 위한 검수용 환경을 따로 두는 경우, 검수 과정에서 발생하는 문제가 라이브 서비스에 영향을 미치지 않습니다.

검수 중인 애플리케이션은 어떻게 검수용 환경을 찾아서 통신할까요? 기존 방식대로라면 검수용 빌드에 검수용 서버의 정보를 포함되어 있을 것입니다. 클라이언트에 서버 정보를 포함시킬 때 유의해야 할 점이 있습니다. 플랫폼의 검수 과정이 시작되면 접수된 빌드를 변경할 수 없습니다. 서버 정보를 바꿔야 하는 경우가 발생한다면 새로운 빌드로 검수 과정을 처음부터 다시 거쳐야만 합니다. 만약 검수 기간이 지연되면 업데이트도 지연되어 신속한 업데이트가 불가능해집니다.

서버 정보를 빌드에 종속시키지 않고 어떤 환경과 통신할지 구성하는 방법

서버 정보 업데이트의 유연성을 위해서는 업데이트 서버 정보가 클라이언트 빌드 외부에 있으면 됩니다. 클라이언트 빌드가 검수 중인 상태라고 하더라도 서버 정보가 빌드에 포함되어 있지 않기 때문에 유연한 운용이 가능해집니다. 서버 정보를 빌드에 종속시키지 않고 클라이언트가 어떤 환경과 통신할지 구성하는 일반적인 방법으로는 두 가지가 있습니다.

첫 번째 방법은 CDN(Content Delivery Network)을 통해 아래와 같이 서버 정보 파일을 전달하는 것입니다.

# dev_server_info.json

{
"is_maintenance" : "true", // 점검 여부
"message" : "지금은 점검 중입니다",
"servers" : [
"login": "https://devlogin.domain.com"
"game" : "ws://devgame.domain.com",
"chat" : "ws://devchat.domain.com"
],
...
}

CDN을 이용하면 별도의 서버를 구성하거나, 소스코드를 작성하는 번거로움 없이 빠르고 간단하게 클라이언트가 통신할 서버를 결정할 수 있습니다. 하지만 CDN에 업로드된 파일은 퍼블릭하게 접근이 가능하기 때문에 유저에게 서버 정보가 유출될 수 있다는 리스크가 있습니다. 서버 정보가 유출될 경우 점검 중에도 서버에 접속을 시도하거나, 아직 정식으로 출시되지 않은 버전의 서버에 접근하는 등 유저가 비정상적인 방식으로 서버에 접근할 가능성이 생기게 됩니다.

두 번째 방법은 서버사이드에서 클라이언트가 통신할 환경을 매칭시켜주는 Launcher 시스템을 구축하는 것입니다. 서버로부터 통신할 경로를 받아오기 때문에 CDN을 이용하는 방법과 달리 정보 유출 가능성이 적기 때문에 보다 권장되는 방법입니다. 단, Launcher 시스템을 구축하기 위한 인프라를 구성해야 한다는 단점이 있습니다.

Launcher 시스템의 핵심은 서버사이드에서 서버 정보를 가지고 있다는 점입니다. 서버 정보는 Redis에 Key-Value 형태로 저장되어 있을 수도 있고, S3에 json 파일 형태로 저장되어 있을 수도 있습니다. 서버에서 환경변수로 저장하는 방식을 사용할 수도 있습니다. 저장 방식은 상황에 맞추어 유리한 방식을 채택할 수 있습니다. 서버 정보가 클라이언트에 종속되지 않으면서 Launcher환경 내부에 저장되어 퍼블릭하게 접근할 수 없는 형태만 갖추면 됩니다.

Launcher 시스템의 대략적인 프로세스는 아래 그림과 같습니다.

Process of Game Launcher System

먼저 클라이언트는 게임 서버에 접속하기 전 Launcher 서버에 Request를 보냅니다. 이 Request에는 클라이언트의 정보가 포함됩니다. Launcher 서버에 전달될 클라이언트 정보로는 빌드 버전, 디바이스의 OS, 애플리케이션 언어 설정 등이 있습니다. 또한 특정 게임임을 알 수 있도록 gamecode와 같은 항목을 추가하여, 통합 Launcher를 만들어 관리를 할 수도 있습니다.

# request payload sample

{
"version" : "1.1",
"os" : "ios",
"language" : "ko"
}

Launcher 서버는 이 정보를 기반으로 서버 정보를 Response로 반환합니다. 1.1 version의 애플리케이션이 라이브 중이고, 1.2 version의 애플리케이션을 업데이트해야한다고 가정합니다. 이 경우에 Launcher 서버는 1.1 version 클라이언트의 Request에 대해서는 라이브서버 정보를, 1.2 version 클라이언트의 Request에 대해서는 검수용 서버 정보를 반환할 것입니다. 클라이언트는 Launcher 서버로부터 전달받은 서버 정보를 기반으로 게임 서버에 요청을 보냅니다. 앞서 언급했던 경우에서 1.2 version의 클라이언트는 검수용 서버에 요청을 보내게 될 것입니다.

Launcher 시스템 인프라를 구축하는 방식

Launcher 시스템 인프라를 구축하는 방식은 다양합니다. 이 중 대표적인 구성 패턴 두 가지를 소개드리겠습니다. 첫 번째 패턴은 API Gateway와 Lambda를 활용한 Serverless 구성이고, 두 번째 패턴은 EC2에 직접 게이트웨이 서버를 띄우는 구성입니다.

우선 Serverless 방식입니다. Lambda에 Launcher 로직을 구현합니다. Launcher 시스템은 클라이언트 정보에 따라 서버 정보를 반환하는 단순한 로직이기 때문에 Lambda의 사용 사례로 적합합니다. API Gateway를 통해 클라이언트의 요청을 Lambda로 전달합니다.

Serverless Pattern for Game Launcher

서버 정보는 ElastiCache for Redis에 저장합니다. 보안을 위해 Redis는 프라이빗 서브넷에 위치시키고 퍼블릭 서브넷의 Bastion Host나 OP Tool을 통해서 관리자만 접근할 수 있게 설정하는 것을 권장합니다. 서버 정보를 저장하는 방식 중 Redis를 선택한 이유는 운영 툴을 통해 편리하게 데이터 설정이 가능하고, 인메모리 DB의 특성 상 접근 속도가 빠르며, 프라이빗 서브넷에 있어 보안적으로 이점이 있기 때문입니다.

아래는 Launcher를 간략하게 구현한 Lambda 함수 샘플 소스코드입니다. Request로 클라이언트 정보를 받아서 Redis에 저장된 서버 정보와 매칭한 다음 함수의 Response로 적합한 서버 주소를 반환합니다.

import redis from "redis";

// redis connection config
const redisClient = redis.createClient({
url: "redis://<redis-endpoint>:6379",
});

// redis connect
redisClient.connect();

export const handler = async(event) => {

// get inspection status
const isMaintenance = event["is_maintenance"]
let message = isMaintenance ? "점검중입니다" : "서비스중입니다";

// get version from request
const version = event["app_version"];
console.log(version);
let serverAddress = "";

// match server address with version
switch (version) {
case "v.1.4":
serverAddress = await redisClient.get("dev");
break;
case "v.1.3":
serverAddress = await redisClient.get('qa');
break;
case "v.1.1":
serverAddress = await redisClient.get('live');
break;
case "v.1.2":
serverAddress = await redisClient.get('review');
break;
default:
message = "앱 버전이 너무 낮습니다. 업데이트를 위해 마켓으로 이동합니다.";
break;
}

// response with server address
const response = {
statusCode: 200,
body: JSON.stringify({
message: message,
server_address: serverAddress
}),
};
return response;
};

Lambda URL로 바로 Lambda 함수에 접근할 수도 있지만 API Gateway를 통해 Lambda에 접근하는 것은 Lambda는 인증서 적용이 불가능하고 AWS 보안 서비스인 WAF 역시 적용이 안되어 보안적인 이슈가 있기 때문입니다. 따라서 Lambda와 API Gateway를 연동하여 사용해야 합니다.

Serverless 방식을 사용할 경우의 유의해야 할 점으로는 API Gateway와 Lambda에 Request 제한이 있습니다. API Gateway의 처리량 할당량은 초당 10,000건의 요청입니다. Lambda 함수의 동시 실행은 기본적으로 1,000번이 할당되어 있습니다. 동시성이 최대에 도달하면 추가 요청에 대해서 조절 오류(상태 코드: 429)가 발생합니다. 기본 할당량은 AWS에 요청하여 증가시킬 수 있기 때문에 기본 할당량 이상의 요청이 예상되는 경우 미리 증가 요청 신청을 하는 것이 좋습니다.

EC2 Usecase for Game Launcher

EC2에 직접 게이트웨이 서버를 띄우는 패턴은 Serverless 방식과 달리 인스턴스를 적합한 스펙으로 프로비저닝해야 합니다. 게이트웨이 서버를 EC2에 세팅하고 Load Balancer를 통해 EC2와 통신합니다.

EC2를 이용할 경우 Serverless 패턴보다 관리포인트가 많습니다. 소스코드만 업로드하면 되는 Lambda와 달리 EC2는 서버 프로비저닝부터 런타임 세팅까지 보다 많은 부분을 직접 제어해야 합니다. 대신 제어할 수 있는 요소가 많은 만큼 Launcher 서버의 스펙과 같은 선택지가 Serverless 패턴에 비해 많습니다.

Launcher 시스템 구성 패턴으로 첫 번째로 CDN, 두 번째로 Serverless, 세 번째로 EC2를 통한 방식을 설명드렸습니다. 아래는 세 가지 구성 패턴을 비교한 표입니다. 각각의 장단점에 고려하여 적합한 패턴으로 Launcher 시스템을 구축하면 됩니다.

마치며

지금까지 Game Launcher 시스템을 활용한 서버 매핑에 대해 알아 보았습니다. 서버 정보를 빌드에 종속시키지 않고 클라이언트가 어떤 환경과 통신할지 구성하는 방법 및 Launcher 시스템 구성 패턴에 대해 간단하게 기재 해 보았는데, 게임 애플리케이션 개발 및 검수 시 참고가 되면 좋을 것 같습니다.

--

--