내일배움캠프 Node.js 트랙 57일차
실시간 멀티 플레이 게임 서버 아키텍처
클라이언트 - 서버 모델
서버의 아키텍처를 분류하는 방식에는 여러가지가 있겠지만, 그 중에서도 대분류를 말하자면 클라이언트-서버 모델이라고 할 수 있겠다. 기존에 우리가 클라이언트라고 부르던 호스트는 플레이어의 컴퓨터, 그 중에서도 게임 소프트웨어라는 애플리케이션이 된다. 그리고 서버는 그들에게 게임에 필요한 리소스를 제공하고, 연결을 관리하는 게임 서버로서 역할한다.
분산 서버
이제 더 작은 분류로 들어가 보자. 실시간 멀티 플레이 게임의 서버의 특징은 무엇일까.
아무래도 실시간성과 안정성을 유지하는 게 매우 중요할 것이다. 이쪽 장르의 게임들이 트래픽을 관리하기 위해 흔히 사용하는 아키텍처는 바로 분산 서버 모델이다. 말 그대로 서버를 하나가 아니라 분산 시켜서 하나의 시스템처럼 동작하도록 설계한 구조이다. 멀티 서버의 개념을 확장시킨 것으로, 특이한 점이 있다면 각 서버가 특정 기능이나 데이터 세트를 담당할 수 있다는 점이다. 또 멀티 서버가 다소 중앙집권적인 것에 반해 멀티 서버는 보다 개별적으로 동작한다.
분산 서버는 멀티 서버로부터 발전된 개념이므로 실제 구현에서는 두 개념이 혼합되어 사용되는 경우가 많다. 어쨌거나 실무에서 중요한 건 두 개념을 가르는 것보다도 성능과 확장성이니 말이다.
모바일 오픈월드 RPG, 듀랑고의 게임 서버 모델 - 2014
[NDC14] “모든 서버는 죽는다” 오픈월드 RPG 듀랑고의 ‘구멍 없는’ 서버 만들기
[야생의 땅: 듀랑고] 서버 아키텍처 Vol. 2 (자막) | PPT
[NDC 18] 서버 디렉터가 직접 답했다, '듀랑고' 출시 초기 서버 문제의 원인 : 네이버 블로그
[NDC 18] 서버 디렉터가 직접 답했다, '듀랑고' 출시 초기 서버 문제의 원인
공룡, 생존, 개척. 독특한 게임 소재로 출시 이전부터 이목을 끌었던 <야생의 땅: 듀랑고>. 기대가 ...
blog.naver.com
많은 이들의 기대와 관심을 모았던 듀랑고라는 게임을 기억하는가? 대학 시절 아크 서바이벌(스팀 생존 게임)에 대한 추억이 있던 나 또한 듀랑고의 출시를 꽤나 기대했던 편이었다. 게임 커뮤니티 인벤에서 열심히 정보를 구하던 시절도 있었지만, 끝이 다소 씁쓸했다는 것이 기억의 마지막 단락이다.
그로부터 오랜 시간이 지나 내가 막상 게임 서버 개발에 도전해보게 되었으니, 듀랑고의 게임 서버 아키텍처가 어땠는지 알아보고 싶다는 생각이 들었다. 다행히 NDC에 발표자료가 남아있었고, 이를 통해 추억 속으로 사라진 게임의 서버 아키텍처를 살펴볼 수 있었다.
서버 설계 목표와 원칙
듀랑고의 서버 개발진은 죽지 않는 서버란 없다는 가정 아래 서버 구조를 고민했다고 한다. 그들은 그들이 만드는 게임 세계가 끊임없이 영속성 있고 일관적이길 바랐다.
그런 세계를 만들기 위한 첫 번째 설계 목표는 높은 가용성이다. 연간 다운타임 5.5분 미만을 목표로 잡았다고 한다.
두 번째 설계 목표는 높은 신축성이다. 유저의 접속량에 따라 서버가 즉각적으로 확장하고 축소되는 신축성을 바랐다고, 그래서 이들 개발진은 손쉽게 서버를 증설하거나 감축하기 위해 아마존 웹 서비스를 선택했다고 한다.
SPOF(단일장애지점)을 제거하라. 부분적 장애를 허용하라.
설계 목표 뒤에 따르는 건 현실적인 문제를 해결하기 위한 고민이다. 서버에 가장 큰 위협 중 하나는 SPOF. 한 곳이 뚫림으로써 서버 전체가 위태로워지는 것이야 말로 가장 경계해야 하는 위험 중 하나이다.
보통 SPOF의 해결법이라고 하면 다들 알고 있는 이중화, 다중화가 있다. 서버를 분산시켜 유사시를 대비하는 것이다.
그러나 위에서 보았던 서버 아키텍처를 다시 자세히 살펴보면 이중화되지 않은 지점이 엿보인다. 바로 중앙서버나 캐시, DB 쪽이 그러하다.
이러한 철학으로 서버를 개발하던 개발진들은 14년도를 지나 16년도에 접어들면서, 예상 외로 단일 서버 체제로의 전환을 맞이하게 된다.
분산 서버에서 단일 서버로 - 2016
이흥섭 테크니컬 디렉터의 깃헙 레포지토리에 따르면, 듀랑고의 개발진들은 모든 요소를 이중화하려고 노력했다고 한다. 그러면서도 끊임 없는 세계를 구현해야 했으니 분산 서버로 구현될 것 같던 그들의 서버는 단일 서버의 형태로 변화를 맞이하게 된다.
듀랑고의 개발진들은 서버를 여러 개 만드는 게 아니라 게임 서버의 노드를 여러 개 분산시킴으로써 영속적인 서버를 가능케 하고자 했다.
노드란 서버 내에서 특정 역할을 수행하는 개별적인 구성 요소로, 한 서버에 여러 노드가 존재할 수도 있고, 여러 서버에서 노드들이 협력하여 동작할 수도 있다. 그리고 중앙서버의 중계 없이도 게임서버 노드끼리 통신시키기 위해 ZeroMQ를 도입했다는데, 이는 게임 노드 간에 직접적인 P2P(peer-to-peer) 또는 분산 메시징 형태의 통신을 구현했다는 의미이다.(기초 소개 - ØMQ Korea)
현실과의 타협 - 2018
분산 서버로의 회귀
2018년 드디어 출시된 듀랑고는 2016년 NDC에 발표된 내용에서 조금 변화한 모습이었다. 단일 서버로의 목표가 좌절되고, 다섯 종류의 서버로 운영되고 있었다. 사실 출시 초기에는 단일 서버가 맞았지만, 아래에서 서술할 많은 어려움 때문에 결국 다중화의 길로 돌아가게 되었다고 한다.
Couchbase의 명암
다만, 듀랑고를 서비스 초기에 중단 사태로 이끈 것은 서버의 형태뿐만은 아니었다고 한다. 오히려 초반에 큰 문제를 일으킨 건 2014년에 선택한 Couchbase라는 NoSQL 데이터베이스 때문이었다고 한다. Couchbase는 고성능 분산 NoSQL 데이터베이스인데, 이는 모든 요소를 이중화하겠다는 개발 철학에 맞물려 선택된 DB였다.
Couchbase는 문서(JSON) 기반 데이터 저장소와 키-값 저장소의 기능을 결합하여 빠른 성능과 유연성을 제공한다고 알려져 있다. 메모리 저장 방식이라 읽고 쓰기가 매우 빨라서 실시간 애플리케이션에서 탁월한 성능을 제공한다고 하는데, 사실 2014년 발표 자료에서도 언급된 치명적인 단점이 하나 있었다. 그건 바로 색인 속도가 느려서 잦은 조회와 갱신에는 적합하지 않고 디스크와의 동기화 작업이 많으면 쓰기 성능이 저하될 수 있다는 것이었다.
단일 채널의 한계
그리고 또 문제가 되었던 건 단일 채널 내에서의 인구밀도가 적절히 분배되지 않았다는 점이다.
실제로 출시 초반 서버장애의 가장 주요한 원인은 바로 이 인구 과밀 때문이라고 한다.
청크와 메시지큐
왜 인구 과밀이 문제였을까? 그건 듀랑고의 서버 설계가 청크 단위로 이루어졌기 때문이라고 한다. 각 노드는 한 청크의 크기로 동기화가 이루어지는데, 노드와 청크 사이의 동기화를 통해 게임 요소들끼리 서로 자연스럽게 이어지면서도 단일장애지점을 피하는 방식으로 설계되었다.
그러나 이 방식의 문제는, 게임 플레이의 부하는 줄일 수 있을지 몰라도 한 청크에 너무 많은 인구가 몰리게 되면 동기화에 부하가 걸린다는 점이었다.
라이브러리의 함정
듀랑고의 서버가 자주 중단되었던 데에는 다소 슬픈 이유도 포함되어 있었다. 노드 하나가 죽으면 연결되어있던 주변 노드들에서 크래시가 발생했는데 안타깝게도 노드 간 통신에 사용하였던 라이브러리에서 발생한 버그였다고 한다.
기타 여러가지 문제들
이외에도 여러가지 원인으로 듀랑고 서버는 여러 가지 어려움을 겪었다고 한다.
- 접속 대기열 장애
- 데이터 베이스 과부하
듀랑고 개발진이 겪었던 어려움에 대한 자세한 내용은 아래 링크에서 확인해볼 수 있다.
NDC Replay
본 홈페이지에 게재, 공개된 발표자료, 동영상, 이미지, 스크립트 등 일체의 저작물(이하 “저작물”이라 합니다)에 대한 저작권 (2차적저작물작성권 및 편집저작물작성권 포함)은 해당 저작물
ndcreplay.nexon.com
내가 모바일 오픈월드 RPG를 만든다면 어떻게 만들어가야 할까
현직자가 겪은 비화들이 다소 씁쓸하였으나, 새로운 기술을 시도하는 개척자들이 있기에 후발주자로서 많은 것을 배우게 되기도 한다. 여전히 게이머 입장이었다면 절대로 이해하지 못했을 것들이, 서버 개발을 조금씩 배워보고 나니 얼마나 많은 고충이 있었을지 미루어 짐작할 수 있었다.
듀랑고 개발진들의 경험을 교훈 삼아, 실시간 동기화가 필요한 오픈월드 RPG는 어떤 지향점을 가져야할지 고민해 보았다.
우선 SPOF를 경계해야 한다는 개발진의 설계 철학에 동의하는 바, 이중화가 편리한 서버의 경우 최대한 이중화 전략을 구축하고자 한다. 그러나 억지로 분산 데이터베이스를 사용하기보단 이미 검증된 DB를 사용하고 싶었다. 따라서 이미 친숙한 레디스와 MySQL을 사용하되, 여러가지 안전장치를 고려해보았다.
찾아보니 레디스와 MySQL 모두 마스터-슬레이브 복제를 지원한다고 한다. DB 서버를 이를 통해 이중화한다면 장애 발생 시 슬레이브를 승격(Promotion)하여 데이터 손실을 최소화할 수 있을 것이다. 실제로 써본 적이 없어서 이 기술의 성능이 어느 정도일지 감은 잘 오지 않지만, 사용자 많은 두 DB인 만큼 성능의 정보 공유가 어느 정도 되어있을 테고, 내가 만족할 만큼의 이중화 또한 가능할 것으로 생각된다. 이에 더해 AWS에서 지원하는 DB 관련 기능도 있을 테니 사용하면 좋을 것 같다. 정말로 많은 부하가 예상될 때엔 샤딩 또한 필요할 것이다.
'개발일지 > TIL(Today I Learned)' 카테고리의 다른 글
2025-01-22 <더 이상 쓰이지 않는 객체는 어떻게 될까?> (2) | 2025.01.22 |
---|---|
2025-01-21 (1) | 2025.01.21 |
2025-01-17 <멀티 플레이 게임 서버 제작하기> (0) | 2025.01.17 |
2025-01-16 (0) | 2025.01.16 |
2025-01-15 (0) | 2025.01.15 |
댓글