기술 이야기
home
Programming
home

ATCS : 게임 서버로 유입되는 폭발적 API 트래픽 대응을 위한 큐 기반 Throttling 전략

Upload date
2024/01/03
Tag
NXCommand
ATCS
백엔드
개발자
Editor
NXCommand팀_홍길석
Editor is
새로운 기술에 관심이 많은 BE 개발자입니다.
3 more properties

Table of contents

들어가며

인텔리전스랩스의 통합인터페이스실은 플랫폼과 게임을 연결하여 대량의 트래픽을 처리하는 플랫폼 서비스 개발을 목표로 하고 있습니다. 그 중에서 NXCommand팀에서는 여러 플랫폼과 게임 간에 API 연동을 효율화하기 위해 표준화 된 API를 제공하는 NXCommand 서비스를 개발하고 있습니다. NXCommand 서비스를 통해 다양한 게임의 데이터를 실시간으로 조회하거나 제어하는 기능을 제공할 수 있습니다.
본 포스팅을 통해 NXCommand 서비스에서 순간적으로 유입되는 대량의 트래픽을 안정적으로 개별 게임 서버에 전달하기 위해 개발된 ATCS (Active Traffic Control System)의 구조와 동작 방식을 소개하고, 실제 프로덕션 환경에서의 적용 후기를 공유하려고 합니다.
ATCS의 주요 특징을 요약하면 아래와 같습니다.
ATCS는 게임 서버 별로 최대 동시 요청 개수를 지정할 수 있으며, 이는 게임 서버의 에러율과 응답시간 등의 유입 트래픽 상황을 기반으로 정책 관리자에 의해 동적으로 제어됩니다.
요청에 대한 게임 서버 별 대기열 시스템을 도입하여 순간적으로 대량의 트래픽이 유입되더라도 사전에 지정된 최대 동시 요청 개수 만큼만 게임 서버에 전달하는 Throttling 시스템을 구축하였습니다. 또한, 인메모리 기반의 큐를 이용함으로써 큐의 도입으로 인한 오버헤드를 최소화하였습니다.
게임 서버 대기열에서의 예상 대기시간이 신규 요청의 타임아웃보다 큰 경우, ATCS는 신규 요청을 대기열에 등록하지 않고 즉시 429 Too Many Request 에러를 응답함으로써 Rate Limiting 시스템을 구축하였습니다.

1. NXCommand 서비스가 직면한 문제

1-1. NXCommand란?

NXCommand는 중개자 역할을 하며, 다양한 플랫폼과 게임 간에 표준화된 API를 설계하고 제공하여 게임 서버에 API 개발을 요청하고, 플랫폼에는 API 연동을 요청합니다. 그림 1은 플랫폼과 게임 서버 간 표준화된 API를 제공하는 NXCommand의 관계를 도식화한 것입니다.
그림 1: 플랫폼과 게임 서버 간 표준화된 API를 제공하는 NXCommand 관계도 도식화
게임 운영도구, 게임 웹 그리고 게임 이벤트와 같은 플랫폼이 프라시아 전기, 마비노기 그리고 바람의나라와 같은 게임을 대상으로 “사용자 정보 조회”, “사용자 쿠폰 지급”과 같은 명령어를 호출하기 위해 일대일 (1:1) 방식의 개별 연동으로 인해 중복 작업이 다수 발생하였습니다. 이러한 문제를 해결하기 위해 NXCommand 서비스가 등장하였습니다. NXCommand 서비스를 통해 플랫폼과 게임은 서로 다대다 (N:N) 방식의 기존 연동을 쉽게 일대다 (1:N) 방식의 연동으로 전환할 수 있으며, 개별 연동에서 발생하는 중복 작업을 최소화합니다.
예를 들어, 그림 2와 같이 게임 사용자는 자신이 즐겨하는 게임의 아이템을 구입하기 위해 게임 웹사이트 내의 웹상점 페이지에서 원하는 상품을 구입할 수 있습니다.
그림 2: 메이플스토리 웹상점 화면
이처럼 게임 사용자가 웹상점에서 상품을 구매하면 웹상점 플랫폼에서는 게임 사용자가 구입한 상품의 지급을 직접 게임 서버에 요청하는 대신, NXCommand 서비스를 통해 게임 서버에 요청을 전달하게 됩니다.

1-2. 폭발적 트래픽 문제

NXCommand 서비스를 통한 플랫폼과 게임 간 API 연동이 증가하면서 서비스에 유입되는 트래픽도 자연스럽게 증가하였습니다.
다양한 유형의 트래픽이 존재하지만 게임의 점검 종료나 신규 게임의 론칭과 같은 상황에서는 순간적으로 대량의 요청이 유입되는 폭발적 트래픽 (Bursty traffic)이 발생합니다. 이러한 상황에서는 오토스케일링 시스템이 구축되어 있다고 하더라도 해당 서버가 상황을 인지한 후 자동으로 증설되는 과정에서 대기시간이 발생하기 때문에 해당 시간 동안 유입된 트래픽에 대해 서버는 리소스 과다 사용으로 인해 처리 속도가 느려지거나 비정상 동작할 수 있습니다. 그림 3은 NXCommand 서비스의 대시보드 중 일부로, 오전 6시에 갑자기 급증한 트래픽으로 인해 리소스 사용률이 증가한 모습을 나타냅니다.
그림 3: 오전 6시가 되자 갑자기 급증한 트래픽으로 인해 리소스 사용률이 증가한 모습
클라우드 네이티브 (Cloud native)인 NXCommand 서비스는 Amazon EKS 상에서 수십 대의 파드가 상시 구동 중이며 이를 통해 최소 1만 RPS의 트래픽을 수용할 수 있습니다. 그렇지만, NXCommand에서 수용할 수 있는 최대치 만큼의 트래픽이 게임 서버에 그대로 유입될 경우, 해당 게임 서버는 트래픽을 수용하지 못하고 다운될 수 있습니다. 그러면 게임 사용자는 에러 응답을 받거나 장기간 응답을 받지 못하게 되고, 이로 인해 사용자 경험의 만족도는 악화될 것 입니다. 이에 따라, NXCommand팀에서는 외부에서 순간적으로 유입되는 대량의 트래픽을 안정적으로 제어하기 위한 시스템 도입의 필요성이 대두되었습니다.

2. 안정적인 트래픽 제어를 위한 설계 원칙

저희는 앞서 설명한 게임 서버로의 트래픽을 안정적으로 제어하기 위해 다음과 같은 설계 원칙을 수립하였습니다.
1.
다운스트림 호스트로부터 어떠한 대량의 트래픽이 유입되더라도 항상 게임 서버가 수용할 수 있을 정도의 트래픽만을 전달합니다. 예를 들어, 게임 서버가 동시에 최대 100의 요청을 처리할 수 있다면, 1,000 만큼의 트래픽이 유입되더라도 한 번에 100의 요청만 전달합니다.
2.
첫 번째 조건을 만족하면서 주어진 타임아웃 시간 내에 최대한 많은 트래픽을 처리합니다. 예를 들어, 다운스트림 호스트의 타임아웃이 60초로 설정된 경우, 해당 호스트의 요청은 늦어도 60초 내에 처리하는 것을 목표로 합니다.
3.
또한, 각 게임 서버가 동시에 처리할 수 있는 요청의 개수를 동적으로 변경할 수 있어야 합니다. 이는 추후 게임 서버의 에러율과 응답 속도를 기반으로 정책 관리자를 통해 서버가 처리할 수 있는 최대 동시 요청 개수를 제어하기 위해 사용됩니다.
이러한 원칙을 바탕으로 NXCommand 서비스의 트래픽을 개별적인 게임 서버에 안정적으로 전달하기 위해 더 세밀한 트래픽 제어가 가능한 L7 기반의 트래픽 제어 시스템 설계를 진행하였습니다.

3. NXCommand 간략 구조

그림 4는 NXCommand 서비스 구조를 간략하게 도식화한 것입니다.
그림 4: NXCommand 서비스 간략 구조 도식화
NXCommand 서비스를 구성하는 요소 중에 NXCommand Sender (발송 서버)는 플랫폼으로부터 수신한 요청을 게임 서버로 전달하는 역할을 수행합니다. 이 외에도, 다음과 같은 부가기능을 제공하고 있습니다.
쿠폰과 같이 동일한 요청의 중복 실행을 방지하기 위한 트랜잭션 기능
특정 날짜 또는 반복적으로 명령어를 발송하기 위한 명령어 예약 기능

3-1. NXCommand의 게임 서버 식별자 정의

NXCommand 서비스에서 각 게임 서버를 구분하기 위해 기존에 정의된 세 가지 식별자를 조합하여 사용하고 있습니다. 사용되는 세 가지 식별자는 다음과 같습니다.
게임 식별자 - 넥슨에서 관리하는 게임 식별 코드입니다.
타겟 그룹 - 게임에 대한 NXCommand 명령어를 처리하는 서버 그룹입니다. 명령어 별로 요청을 처리하는 주체가 다르기 때문에 타겟 그룹으로 구분합니다.
게임 서버 하위 식별자 - 타겟 그룹 내에서 실제로 명령어를 처리하는 게임 서버 식별자입니다. 서로 다른 타겟 그룹에 동일한 게임 서버 하위 식별자를 가질 수 있습니다.
NXCommand에서는 게임 서버를 식별하기 위해 게임 식별자, 타겟 그룹 그리고 게임 서버 식별자를 콜론 (:)으로 조합하여 단일 식별자를 생성합니다. 예를 들어, 다음 표와 같이 게임 식별자, 타겟 그룹 그리고 게임 서버 식별자가 주어질 때, 게임 서버 하위 식별자를 생성할 수 있습니다.
게임 식별자
타겟 그룹
게임 서버 하위 식별자
게임 서버 식별자
baram
coupon
qa-1
baram:coupon:qa-1
maple
coupon
qa-2
maple:coupon:qa-2
kart
play
stage
kart:play:stage
이러한 게임 서버 식별 정보는 다운스트림 호스트에서 HTTP API의 헤더를 통해 전달하며, 조합된 게임 서버 식별자를 통해 NXCommand 발송 서버는 미리 등록된 업스트림 호스트 주소로 명령어 요청을 전달합니다.

3-2. NXCommand 서비스의 한 가지 문제점

NXCommand 발송 서버는 다운스트림 호스트로부터 전달받은 요청을 별다른 트래픽 제어없이 게임 서버에 전달하였는데, 이로 인해 게임 서버의 상태와 무관하게 요청을 발송해버림으로써 항상 게임 서버가 트래픽 과부하로 다운될 수 있는 위험에 노출되었습니다. 실제로 일부 게임 서버의 경우 종종 발생하는 폭발적 트래픽으로 인해 다운되는 현상이 발생하고 있었습니다.
이러한 문제를 해결하기 위해 갑작스럽게 증가하는 폭발적 트래픽을 일정한 패턴과 속도로 데이터가 흐르는 안정적 트래픽 (Steady traffic) 으로 변환해주는 ATCS (Active Traffic Control System)를 개발하여 NXCommand 서비스에 도입하게 되었습니다.

4. ATCS

ATCS (Active Traffic Control System)는 다운스트림 호스트로부터 유입되는 다양한 형태의 트래픽을 업스트림 호스트 별로 능동적으로 제어하기 위해 만들어진 시스템입니다.
ATCS는 게임 서버의 수용 가능한 트래픽을 개별적으로 제어하기 위해 대기열을 사용합니다. 그림 5는 NXCommand와 ATCS 간의 메시지 대기열 처리에 대한 예시를 도식화한 것입니다.
그림 5: NXCommand와 ATCS 간 메시지 대기열 처리에 대한 예시 도식화
NXCommand 발송 서버가 ① 수신한 요청 메시지는 ② 해당 게임 서버의 전용 대기열에 등록되며, ATCS 스케줄러는 게임 서버 별 스케줄링 정책에 따라 ③ 처리 가능한 경우 대기열에서 메시지를 인출하여 ④ NXCommand 발송 서버에게 발송 통보를 수행할 수 있습니다. 그렇게 전달받은 메시지를 NXCommand 발송 서버는 ⑤ 게임 서버에 발송합니다.
ATCS에서 관리하는 게임 서버 별 스케줄링 정책은 동시 요청 개수를 기반으로 운영됩니다.

4-1. ATCS에서 동시 요청 개수란?

다운스트림 호스트로부터 요청을 받은 서버는 업스트림 호스트로 요청을 전달합니다. 이때, 업스트림 호스트는 요청을 처리하는 과정에서 지연이 발생할 수 있으며, 다운스트림 호스트 및 서버는 무한정 대기하는 현상을 방지하기 위해 408 요청 타임아웃을 설정합니다.
서버는 다양한 다운스트림 호스트로부터 요청을 받게되며, 이전 요청에 대한 응답을 기다리지 않고 이후 유입된 요청을 발송할 수 있습니다. 이때 업스트림 호스트는 응답의 지연이 길어지는 경우 반환하는 응답 대비 수신하는 요청의 개수가 점점 증가할 수 있는데, 이로 인해 업스트림 호스트는 CPU, 메모리 사용량 및 네트워크 트래픽이 증가하면서 최악의 경우 서버가 다운될 수 있습니다.
본 포스팅에서는 이와 같이 특정 시점에서 업스트림 호스트가 수신한 전체 요청의 개수에서 응답을 반환하지 않는 요청의 개수를 동시 요청 개수라고 정의하였습니다. 동시 요청 개수가 많아질수록 게임 서버에서 동시에 처리하고 있는 요청의 개수가 증가한다는 의미이며, 이로 인해 리소스 사용률이 높아져 시스템의 비정상 동작으로 이어질 수 있습니다.
ATCS에서 408 요청 타임아웃을 예방하기 위한 조치 다운스트림 호스트가 요청한 게임 서버의 트래픽이 과도한 상황에서는 게임 서버 대기열에 메시지가 많이 쌓일 수 있습니다. 이로 인해, 대기열에서 메시지를 인출하는 시점에 다운스트림 호스트가 408 요청 타임아웃으로 연결을 이미 종료한 상태에 놓일 수 있는데, ATCS에서는 메시지를 대기열에 등록하기 전에 요청 타임아웃 시간과 대기열의 예상 대기시간을 비교하여 타임아웃 값이 더 짧으면 대기열에 메시지를 등록하지 않고 즉시 429 Too Many Requests 에러를 응답하여 408 요청 타임아웃 문제를 예방하였습니다.

4-2. ATCS 구성요소

ATCS는 요청 메시지를 대기열에 등록하는 ATCS SDK와 게임 서버의 대기열을 관리하는 ATCS 스케줄러, 그리고 게임 서버 별 허용 가능한 트래픽을 동적으로 제어하는 ATCS 정책 관리자로 구성되어 있습니다. 그림 6은 ATCS의 구성요소를 도식화한 것을 나타냅니다.
그림 6: ATCS 구성요소 도식화
ATCS SDK - ATCS SDK는 NXCommand 발송 서버에서 ATCS에 필요한 기능을 제공하는 모듈로, 요청 메시지의 대기열 등록과 같은 모든 ATCS 작업은 SDK를 통해 이루어집니다.
ATCS 스케줄러 - ATCS 스케줄러는 게임 서버가 처리 가능한 상태가 되었을 때 대기열로부터 요청 메시지를 인출하여 트래픽을 제어합니다.
ATCS 정책 관리자 - ATCS 정책 관리자는 게임 서버의 상태를 실시간으로 모니터링하여 게임 서버가 감당할 수 있는 트래픽 만큼을 전달하도록 트래픽 구성 정보를 관리합니다. 게임 서버가 트래픽 과부하로 보이는 경우 해당 게임 서버의 수용 가능한 트래픽을 줄이거나, 여유가 있으면 수용 가능한 트래픽을 늘리는 작업을 수행합니다.
앞서 설명드린 NXCommand 발송 서버는 다운스트림 호스트로부터 수신한 요청 메시지를 ATCS SDK를 통해 게임 서버 대기열에 등록하며, 이후 ATCS 스케줄러로부터 메시지의 발송 통보를 수신할 때 까지 일정 시간 대기합니다.

4-3. ATCS가 요청 트래픽을 제어하는 방법

NXCommand 발송 서버가 ATCS를 통해 트래픽을 제어하는 과정을 조금 더 깊게 알아보겠습니다. ATCS는 ATCS SDK와 ATCS 스케줄러 간 효율적인 통신을 위해 Pub/Sub 모델을 사용합니다. NXCommand 발송 서버와 ATCS 스케줄러는 그림 7과 같은 순서를 통해 요청 트래픽을 제어합니다.
그림 7: NXCommand와 ATCS 간 요청 처리를 위한 작업 순서 도식화
1.
NXCommand 발송 서버는 다운스트림 호스트로부터 요청을 수신합니다.
2.
NXCommand 발송 서버는 수신한 요청 메시지를 대상 게임 서버의 대기열에 등록합니다.
3.
NXCommand 발송 서버는 ‘메시지 대기열 등록’ 채널에 이벤트를 발행 (publish) 하여 ATCS 스케줄러에게 전달합니다.
4.
이벤트를 수신한 ATCS 스케줄러는 캐시에 저장된 대상 게임 서버의 현재 요청 개수를 검사하여 현재 신규 요청을 처리할 수 있는 상태인지 판단합니다,
5.
ATCS 스케줄러는 게임 서버 대기열에 등록된 메시지를 인출합니다.
6.
ATCS 스케줄러는 대기열에서 인출한 메시지를 대상 NXCommand 발송 서버의 메시지 대기열에 전달합니다.
7.
ATCS 스케줄러는 ‘메시지 발송 통보’ 채널에 이벤트를 발행하여 NXCommand 발송 서버에게 전달합니다.
8.
이벤트를 수신한 NXCommand 발송 서버는 발송 서버의 메시지 대기열에 등록된 메시지를 인출합니다.
9.
NXCommand 발송 서버는 대기열에서 인출한 메시지를 게임 서버에 발송합니다.
10.
발송 작업을 마친 후, NXCommand 발송 서버는 ‘메시지 발송 완료 통보’ 채널에 이벤트를 발행하여 ATCS 스케줄러에게 메시지를 전달합니다.
11.
이벤트를 수신한 ATCS 스케줄러는 캐시에 저장된 대상 게임 서버의 현재 요청 개수를 감소시킵니다.
주목할 점으로, ATCS 스케줄러는 ‘메시지 발송 완료 통보’ 이벤트를 통해 게임 서버의 동시 요청 개수와 같은 트래픽 정보를 갱신함으로써 이후 요청에 대한 게임 서버로의 메시지 발송 가능 여부를 실시간으로 판단할 수 있습니다.

4-4. ATCS가 채택한 영구 저장소와 캐시

ATCS 스케줄러는 실시간으로 게임 서버의 트래픽 정보를 관리하기 위해 캐시 (Cache)로서 AWS에서 제공하는 Redis 기반의 서비스인 Amazon ElastiCache를 사용하였습니다. 또한, 영구 저장소 (Persistent Storage)로 Amazon S3를 사용하였습니다.

4-5. ATCS 영구 저장소

ATCS는 게임 서버 별로 가능한 최대 동시 요청 개수를 의미하는 max_concurrency 값을 영구 저장소에서 관리합니다. 예를 들어, 게임 “바람의나라”에서는 최대 동시 요청 개수가 10,000건, 게임 “카트라이더: 드리프트”에서는 30,000건으로 저장될 수 있습니다. 이러한 최대 동시 요청 개수는 사전에 게임 측에서 게임 서버의 성능을 기반으로 계산하여 전달한 값을 사용합니다.
{ "rps": { "max_concurrency": 10000 } }
JSON
복사
앞서 설명드린 바와 같이 ATCS 정책 관리자가 게임 서버의 상태를 실시간으로 모니터링하면서 필요에 따라 최대 동시 요청 개수를 능동적으로 제어합니다.
ATCS 정책 관리자가 S3에 저장된 최대 동시 요청 개수를 업데이트하면 파일의 ETag가 변경되는데, ATCS 스케줄러는 주기적으로 S3의 게임 서버 별 설정 정보 파일을 스캔하면서 ETag가 변경된 파일을 찾고, 변경된 설정 정보를 ElastiCache에 반영합니다.

4-6. ATCS 캐시

Redis는 오픈 소스 인메모리 데이터 구조 저장소로, 속도와 유연성이 뛰어나 캐싱, 실시간 분석, 메시지 큐 등에 자주 사용됩니다. 데이터베이스 쿼리 결과와 같이 자주 액세스하는 데이터를 Redis에 캐싱하면 트래픽이 급증할 때 백엔드 서버의 부하를 크게 줄일 수 있습니다.
키-밸류 형태의 저장소인 캐시에는 앞서 설명드린 최대 동시 요청 개수와 현재 요청 개수를 아래와 같이 보관하고 있습니다. 다음은 게임 서버 식별자 “baram:coupon:qa-1”의 최대 동시 요청 개수와 현재 요청 개수의 키를 나타내고 있습니다.
game_server_id:{baram:coupon:qa-1}:max_concurrency game_server_id:{baram:coupon:qa-1}:current_request_count
Plain Text
복사
두 키의 값은 String 타입이나, Redis에서는 INCR 또는 DECR 명령어를 통해 마치 숫자처럼 값을 증가시키거나 감소시킬 수 있습니다.
마찬가지로, 게임 서버 별 대기열과 대기시간에 대한 키는 아래와 같이 표현합니다.
atcs_message_queue_id:{baram:coupon:qa-1} atcs_message_queue_id:{baram:coupon:qa-1}:queue_waiting_time_ms
Plain Text
복사
List 타입인 대기열의 길이는 LLEN 명령어를 통해 조회가 가능하며, String 타입인 대시시간 조회는 GET 명령어를 통해 가능합니다.
추가적으로, 예시에서 게임 서버 식별자 사이에 중괄호를 추가한 이유는 Redis에서 제공하는 ‘해시 태그’ 기능을 통해 Redis 클러스터에서 키의 해시 슬롯을 계산하기 위함입니다. 이를 통해, Redis 클러스터에서 동일한 게임 서버 식별자는 항상 동일한 샤드에서 처리되는 것을 보장할 수 있습니다.
이렇게 캐시에 등록된 게임 서버의 현재 요청 개수를 기반으로 ATCS 스케줄러는 게임 서버의 요청 트래픽을 제어합니다.

ATCS 스케줄러의 캐시 워밍

ATCS 스케줄러는 캐시 워밍 (Cache warming) 방식으로 초기화 시점에 영구 저장소에서 전체 게임 서버의 최대 동시 요청 개수를 가져와 캐시에 갱신합니다. 그리고 영구 저장소에 보관 중인 게임 서버의 설정 파일을 주기적으로 조회하면서 ETag가 로컬 캐시에 보관하고 있는 값과 다를 경우, 영구 저장소의 설정 정보를 캐시에 동기화하는 작업을 수행합니다.
ATCS 정책 관리자는 게임 서버의 요청 처리 결과를 실시간으로 모니터링하면서 응답 시간과 에러율을 바탕으로 게임 서버의 최대 동시 요청 개수를 동적으로 제어합니다. 예를 들어, “바람의나라” 게임 서버의 최대 동시 요청 개수가 10,000인 상태에서, 지난 1분 간 응답시간이 10% 증가하거나 에러율이 10% 증가했을 때, 이러한 지표를 기반으로 최대 동시 요청 개수를 9,000으로 10% 감소시킬 수 있습니다.
아직 ATCS 정책 관리자는 프로덕션 환경에 배포되지 않은 상태로, 올해 안에 개발 및 프로덕션 환경 배포를 목표로 하고 있습니다.

4-7. ATCS가 트래픽을 능동적으로 제어하는 방법 (with Pub/Sub)

ATCS는 Redis에서 제공하는 Pub/Sub 기능을 통해 게임 서버의 트래픽을 능동적으로 제어하기 위해 아래의 세 가지 이벤트를 사용하고 있습니다. 그림 8은 NXCommand와 ATCS 간 이벤트 발행을 도식화한 것을 나타냅니다.
그림 8: NXCommand와 ATCS 간 이벤트 발행 도식화

이벤트 ① ATCS 메시지 대기열 등록

ATCS 스케줄러는 캐시에 등록된 게임 서버 별 트래픽 정보를 활용하여 ‘ATCS 메시지 대기열 등록’ 이벤트를 수신하면, Redis의 Function에 등록된 LuaScript를 통해 다음의 작업을 원자적으로 수행합니다:
1.
게임 서버의 현재 요청 개수가 최대 동시 요청 개수보다 작은지 확인합니다.
2.
게임 서버의 대기열에서 한 개의 메시지를 인출합니다.
3.
게임 서버의 현재 요청 개수를 1 증가시킵니다.
4.
대기열에서 인출한 메시지를 반환합니다.
만약 첫 번째 작업에서 현재 요청 개수가 최대 동시 요청 개수와 동일하다면, ATCS 스케줄러는 LuaScript를 종료하고 ‘게임 서버 요청 개수 감소’ 이벤트를 수신할 때 까지 대기합니다.

이벤트 ② ATCS 메시지 발송 통보

ATCS 스케줄러가 게임 서버 대기열에서 메시지 성공적으로 인출하면 해당 메시지는 ‘ATCS 메시지 발송 통보’ 이벤트를 통해 NXCommand 발송 서버에게 전달됩니다. 더불어, NXCommand 발송 서버는 즉시 게임 서버에게 요청 메시지를 발송합니다.

이벤트 ③ ATCS 메시지 발송 완료

NXCommand 발송 서버가 게임 서버로 요청 메시지를 발송하고 응답을 받으면, ATCS SDK를 통해 ATCS 스케줄러에게 ‘ATCS 메시지 발송 완료’ 이벤트를 발행합니다. 이벤트를 수신한 ATCS 스케줄러는 아래 작업을 순차적으로 수행합니다:
1.
게임 서버의 현재 요청 개수를 1 감소시킵니다.
2.
게임 서버 대기열에 메시지가 하나라도 존재하는지 확인하고, 존재한다면 ‘게임 서버 요청 개수 감소’ 이벤트를 발행합니다.
만약 ’ATCS 메시지 대기열 등록’ 이벤트에서 현재 요청 개수가 최대 동시 요청 개수에 도달한 경우, ATCS 스케줄러는 대기열에서 메시지를 인출하지 않고 대기 상태에 놓입니다. 이 상태를 해소하려면 ATCS 스케줄러가 ‘게임 서버 요청 개수 감소’ 이벤트를 발행해야 합니다.

이벤트 ④ 게임 서버 요청 개수 감소

ATCS 스케줄러는 앞서 소개한 ‘ATCS 메시지 발송 완료’ 이벤트를 처리한 후 해당 게임 서버의 대기열에 메시지가 하나라도 남아있을 경우, ‘게임 서버 요청 개수 감소’ 이벤트를 발행하여 남은 대기열 내 메시지를 처리하도록 트리거링합니다.
트리거된 ATCS 스케줄러는 ‘ATCS 메시지 대기열 등록’ 이벤트를 수신했을 때와 완전히 동일한 작업을 수행하게 됩니다.

4-8. ATCS의 Throttling 및 Rate Limiting 알고리즘

ATCS에서 게임 서버 트래픽을 제어하는 기법은 기존의 Rate Limiting 기법 중에 토큰 버킷 (Token bucket) 알고리즘과 유사하지만 몇 가지 다른 점이 있습니다.
토큰 버킷은 버킷에 토큰이 없을 경우 에러를 응답하지만, ATCS는 대기열을 도입하여 전송 가능한 상태가 될 때 까지 전송을 지연시킴으로써 Throttling 시스템을 구축하였습니다.
토큰 버킷은 일정한 시간마다 토큰이 버킷에 채워지지만, ATCS는 게임 서버에 동시에 전송할 수 있는 요청 메시지의 개수, 즉 동시 요청 개수를 사용합니다. ATCS 스케줄러는 대기열에서 메시지를 인출할 때마다 현재 요청 개수를 1씩 증가시킵니다. 그러나 일정한 시간마다 현재 요청 개수가 자동으로 감소하지 않습니다. 대신, NXCommand 발송 서버가 ATCS 스케줄러에게 ‘메시지 발송 완료’ 이벤트를 발행함으로써 게임 서버의 현재 요청 개수가 감소합니다.
ATCS의 Rate Limiting 기법은 요청 별로 토큰이 제거된다는 점에서 토큰 버킷과 유사하지만, 업스트림 호스트에 전송되는 트래픽의 최대 크기가 균일하다는 점에서는 누수 버킷 (Leaky bucket)과 유사하다고 볼 수도 있습니다. 다시 말해, 게임 서버는 NXCommand 발송 서버로부터 받는 최대 동시 요청 개수가 일정하게 유지됩니다.

5. ATCS 트래픽 제어 시연

지금까지 설명드린 ATCS 구조를 토대로 게임 서버로의 트래픽을 제어하는 작업의 간략한 시연을 살펴보겠습니다.

5-1. 시연 조건

다음과 같은 조건으로 ATCS의 시연을 진행하였습니다.
게임 서버의 최대 동시 요청 개수: 100건
게임 서버의 요청 별 예상 처리시간: 10초
실제 동시 요청 개수: 1,000건

5-2. ATCS 시연 결과

ATCS의 트래픽 제어 시연 결과를 그래프로 시각화하면 그림 9와 같습니다.
그림 9: ATCS의 트래픽 제어 시연 결과 그래프
ATCS 스케줄러는 1,000건의 요청 중 최초로 유입된 100건을 우선적으로 게임 서버에 발송하도록 스케줄링합니다.
게임 서버는 명령어 처리가 완료왼 후 10초 동안 100건의 요청에 대한 응답을 반환하며, ATCS 스케줄러는 이후 순차적으로 100건씩 대기열에서 요청 메시지를 인출하여 게임 서버로 발송하도록 스케줄링합니다. 이로 인해 위 그래프 상에서 10초 마다 명령어 처리 개수가 100건 씩 증가하는 형태를 나타냅니다.
게임 서버의 최대 동시 요청 개수는 100건으로 설정되어 있어, ATCS 스케줄러에서 관리하는 게임 서버에 대한 현재 요청 개수는 최대 100까지만 증가하게 됩니다.
결과적으로, ATCS를 사용하지 않은 경우 게임 서버는 1,000건의 요청을 동시에 받으면서 서버 다운이 발생할 수 있습니다. 그러나, ATCS를 활용하면 1,000건의 요청을 120초 동안에 걸쳐 순차적으로 처리하여 서버 다운을 방지할 수 있습니다.

6. 프로덕션 환경에 ATCS 적용하기

실제 프로덕션 환경에서 NXCommand 서비스에 적용한 ATCS가 게임 서버의 트래픽을 제어했던 간단한 사례를 공유드리겠습니다.

6-1. ATCS 적용 사례

최근 ATCS가 프로덕션 환경에 배포되면서 시스템 안정화 기간 동안 모든 게임 서버의 최대 동시 요청 개수를 실제로 도달할 수 없는 수치인 백만 건으로 설정하여 사실 상 미사용 상태에서 운영되고 있었습니다.
이런 상황에서, NXCommand 서비스를 통해 A 게임의 운영 서버로 유입되는 요청에서 간헐적으로 ‘503 Service Unavailble’ 에러가 발생하는 것을 관찰하여 확인한 결과, 게임 서버가 처리할 수 있는 분당 요청 개수가 300건에 불과하며, 그 이상의 요청이 유입되는 경우 서버가 다운되고 있는 상황이라는 것을 알게되었습니다.
이에 따라, 폭발적 트래픽이 A 게임 서버로 유입되는 사태에 대비하기 위해 ATCS에서 A 게임 서버로 유입되는 동시 요청 개수를 200건으로 설정을 해두었습니다. 이로써 아무리 많은 요청이 동시에 유입되더라도 실제 A 게임 서버에는 한 번에 최대 200건씩만 전달되기 때문에 게임 서버의 다운을 방지할 수 있을 것으로 기대하였습니다.
공교롭게도, 그 다음 주에 A 게임에서 웹쿠폰 이벤트가 진행되었는데, 이벤트가 시작한 직후 웹쿠폰 지급과 관련한 트래픽이 NXCommand 서비스에 유입되었습니다. 그림 10은 9월 2일 A 게임에서 오후 7시 30분부터 진행된 웹쿠폰 이벤트에 대한 게임 서버가 수신한 요청 트래픽을 나타냅니다.
그림 10: 오후 7시 30분부터 서서히 증가하는 요청 트래픽
7시 30분 전까지는 유입되는 트래픽이 적었는데, 이후 점진적으로 증가하는 모습을 관찰할 수 있습니다. 미리 설정해둔 최대 동시 요청 개수 덕분에, ATCS 스케줄러는 폭발적 트래픽에 대해 가장 먼저 유입된 200건의 요청을 우선적으로 A 게임 서버로 발송하고, 이후 게임 서버로부터 응답을 받을 때 마다 대기열에 등록된 다음 요청들을 순차적으로 인출 후 발송함으로써 게임 서버의 다운을 방지할 수 있었습니다.
폭발적 트래픽이 유입되는 당시 해당 게임 서버의 현재 요청 개수 조회 결과는 그림 11과 같습니다.
그림 11: 게임 서버의 최대 동시 요청 개수와 현재 요청 개수
예상한대로, 최대 동시 요청 개수 (당시 max_rps)는 “200”으로 설정되어 있으며, 현재 요청 개수 또한 “200”으로 설정되어 있어 동시 요청 처리가 사실상 포화 상태였습니다. 이와 같이 현재 요청 개수가 최대 동시 요청 개수에 도달할 경우, ATCS 스케줄러는 발송 통보를 중지함으로써 더 이상 게임 서버에게 메시지를 발송하지 않도록 트래픽을 통제합니다.
아쉬웠던 점
다만, 이 당시 ATCS도 안정화된 상태가 아니다 보니 비정상 동작이 발생하기도 하였습니다. 일부 요청에 대해 트래픽이 유실되면서 게임 서버에서 응답을 반환했음에도 현재 요청 개수가 감소되지 않는 문제가 발생하여 결과적으로 현재 요청 개수가 최대 동시 요청 개수에 고정되는 상황이 발생하였습니다. ATCS에서는 대기열에 대한 대기시간의 타임아웃을 10초로 설정해두었기 때문에 이후 유입되는 모든 요청은 10초 동안 대기 후 타임아웃이 발생하여 게임 서버로 발송되었습니다. 이러한 문제는 현재 지속적인 안정화 작업을 통해 해결되었습니다.

6-2. ATCS 도입 후 회고

트래픽 제어 시스템인 ATCS를 프로덕션 환경에 도입하는 과정에서 느낀 ATCS의 장단점을 간단하게 공유해보겠습니다.

Pros - 게임 서버로의 안정적인 트래픽 제공

NXCommand 서비스에 ATCS를 도입함으로써 게임 서버로 유입되는 폭발적 트래픽을 안정적 트래픽으로 전환할 수 있게 되었으며 NXCommand팀에서는 과도한 트래픽이 NXCommand 서비스에 유입됨으로써 발생할 수 있는 게임 서버의 장애 발생에 대한 걱정을 줄일 수 있게 되었습니다.

Cons - 요청의 평균 처리시간 증가

ATCS를 도입 후 NXCommand 서비스의 평균 요청 처리시간은 전보다 15% 정도 증가하였습니다. 지연 시간의 대부분은 NXCommand 발송 서버와 ATCS 스케줄러가 Pub/Sub 또는 키 값의 설정 및 조회와 같이 Redis와 통신을 수행하는 과정에서 발생하는 유휴 시간에 기인합니다.
따라서, 앞으로 ATCS를 통해 게임 서버의 안정적인 트래픽 처리의 장점을 유지하면서 지연 시간 증가의 단점을 최소화하기 위해서는 Redis와 통신하는 횟수를 줄이는 것이 중요합니다.

7. 추후 계획

7-1. ATCS 정책 관리자 개발

앞서 설명드린 바와 같이, 게임 서버 별 최대 동시 요청 개수를 관리하는 ATCS 정책 관리자를 개발할 예정입니다. ATCS 정책 관리자는 게임 서버의 모든 요청에 대한 평균 응답시간, 에러율을 수집 및 집계하여 주기적으로 게임 서버의 최대 동시 요청 개수를 수용 가능한 수준으로 조절합니다.

7-2. 모니터링 기능 강화

하반기에는 ATCS에서 관리하는 게임 서버 별 대기열의 상태를 실시간으로 모니터링하기 위한 대시보드를 개발할 예정입니다. 이를 위해 Prometheus에서 Redis에 저장된 각 게임 서버의 트래픽 상태를 수집하고, Grafana의 대시보드를 통해 엔지니어가 빠르게 상황을 인지하여 장애에 대응할 수 있도록 지원하려고 합니다.

나가며: 맺는 말

NXCommand팀에서 개발한 NXCommand 서비스는 다양한 플랫폼과 게임사이에서 표준화된 API를 설계하고 제공하여 개별 연동에서 발생하는 중복 작업을 최소화합니다. 현재 NXCommand 서비스에는 하루 1,500만 건의 트래픽을 안정적으로 처리하고 있으며, 약 100 여개의 게임 서버가 연동되어 있습니다. NXCommand 서비스를 연동하는 게임과 플랫폼이 계속 늘어남에 따라 유입되는 트래픽도 증가하고 있습니다.
이러한 환경에서 발생할 수 있는 장애를 최소화하기 위해 ATCS가 개발되었습니다. ATCS는 NXCommand에 연동된 게임 서버 별 메시지 대기열을 도입하고 게임 서버 별 동시 요청 개수를 제어함으로써 폭발적 트래픽이 일시적으로 게임 서버에 유입되는 문제를 방지합니다. 예를 들어, A 게임에서는 ATCS에서 사전에 설정한 최대 동시 요청 개수 만큼의 요청만이 게임 서버로 안정적으로 전달되어 웹쿠폰 이벤트에서 발생한 폭발적 트래픽을 안정적으로 변환할 수 있었습니다.
ATCS는 현재 안정화가 지속적으로 이루어지고 있으며, 앞으로는 ATCS 정책 관리자를 개발하여 게임 서버 별 최대 동시 요청 개수를 제어하고, 게임 서버 별 메시지 대기열의 모니터링 기능을 강화하는 작업을 진행할 계획입니다. ATCS에 대한 많은 기대를 부탁드립니다.
긴글 읽어주셔서 감사합니다.

Reference

함께 읽으면 좋은 콘텐츠
Related Sites
 넥슨 게임 포탈
회사 소개
인텔리전스랩스 소개
인재 영입
인텔리전스랩스 블로그 운영 정책
 테크블로그 문의 devrel@nexon.co.kr