나만의 작은 도서관
[TIL][C++] 250618 MMO 서버 개발 39일차: 게임서버에서의 분산 서버 활용법들: MMORPG 게임의 수평 확장 방식: 월드, 채널, 존 본문
Today I Learn
[TIL][C++] 250618 MMO 서버 개발 39일차: 게임서버에서의 분산 서버 활용법들: MMORPG 게임의 수평 확장 방식: 월드, 채널, 존
pledge24 2025. 6. 18. 22:45주의사항: 해당 글은 일기와 같은 기록용으로, 다듬지 않은 날것 그대로인 글입니다.
게임서버에서의 분산 서버 활용법들: MMORPG 게임의 수평 확장 방식: 월드, 채널, 존
매우 바쁜 게임서버
- 게임서버는 굉장히 하는 일도 많고 바쁘다. 유저가 게임에서 이동만 해도 초당 최소 5번의 이동 패킷을 서버에 전송하며, 같은 방에 있는 다른 유저의 이동 패킷들을 초당 최소 5번을 받기 때문이다. 게임의 종류마다 방에 존재하는 유저수가 다르겠지만, 10명 정도로 잡았을 때만 봐도 초당 9*5 = 45개의 패킷을 서버가 한 유저에게 보내야 한다.
- 방이 많아질수록, 같은 방에 존재하는 유저수가 많아질수록 broadcast 하는 횟수와 비용은 점점 커질 것이고, 이를 쳐내는 서버가 받는 부하는 어마어마할 것이다.
- 실제로 하나의 거대한 대륙 또는 월드를 다루는 MMORPG의 경우, 하나의 필드에 존재하는 다른 유저들의 수가 10명 정도가 아닌 50~100명, 많게는 1000명까지도 있을 수 있어야 한다. 1000명의 이동 동기화, 충돌 처리, 스킬 및 전체 채팅 등, 수많은 기능들이 있을 텐데 이 1000명의 유저들이 요청한 수많은 기능들을 전부 처리하고도 게임 서버는 멀쩡할 수 있을까?
동접 3000명만 돼도 못 버티는 게임서버
- 하나의 서버를 굴려서 MMORPG장르의 게임서버의 역할을 하게 하는 것은 한계가 있다. 여러 개의 코어를 병렬적으로 사용하는 멀티 스레드 환경의 프로그램을 제작한다고 해도 3000~5000명 정도의 인원만 수용 가능하지, 동접 10,000명, 20,000~30,000명 정도의 인원은 수용할 순 없다.
- 대표적인 멀티 스레드 환경 구축에 친화적인 IOCP 소켓 모델을 사용한다고 해도 똑같다. 싱글 스레드보다 많은 인원들을 수용할 수 있게 될 뿐이지, 그것이 우리가 원하는 10,000명이 넘어가는 동접자를 받을 수 있다는 것을 의미하진 않는다.
- 멀티 스레드 환경의 프로그램으로 커버 치는데 한계가 있다는 것은, 결국 하드웨어의 문제라는 걸까? 하드웨어, 즉, RAM의 용량과 스펙을 높이고, CPU의 스펙을 올리는 등의 scale-up 방식으로 해결할 수 있는 걸까?
- 당연히 아니다. scale-up도 한계가 있는 방식으로, 하드웨어 성능을 높이는데도 한계가 있고, 유의미할 정도로 하드웨어 스펙을 높일 수 있다고 해도, 멀티 스레드 환경에서 기대한 만큼 성능이 나올 거란 보장도 크게 없다.
scale-out방식으로 서버를 수평 확장
- 결국 더 많은 동접자를 받기 위해선, 수평적 확장인 scale-out 방식을 선택하여 분산 서버를 만들어야 한다. 문제는 우리가 만들고자 하는 게임은 MMO RPG 장르라는 것이다.
- “한 판”의 개념이 있는 레이싱 게임, FPS 게임, 격투 게임의 경우, 그 유저들만 특정 서버로 보내 한 판의 게임을 즐기도록 하면 된다. AWS와 같은 곳에서 빌린 데디케이티드 서버에 서버 프로그램이 깔고 그곳에 유저들은 던져놓으면 된다는 것이다.
- 하지만 MMO RPG 같은 경우, PVP를 하거나 인스턴스 던전 및 레이드에 들어가지 않는 이상, 한 판이라는 개념은 존재하지 않는다. 어드벤처 속성을 지니고 있으니, 다른 맵으로 넘어갔을 때 그곳에 있던 새로운 사람들과 만나게 되는 것이다. 맵을 이동하고, 대륙을 이동할 때마다 새로운 유저를 만나고 소통한다니… 조금은 당혹스러울 수밖에 없다.
MMO RPG 게임의 수평 확장 방식: 월드, 채널, 존
- MMO RPG 게임의 경우, 조금 다르게 접근해야 한다. “한 판”이라는 개념이 따로 없으니 유저들의 상태 동기화를 가져가면서도, 한 서버가 버틸 수 있는 정도의 수용 인원을 배치해야 한다. 이 방식에는 크게 2가지 방식(채널, 존)이 있고, 약간은 개념이 다른 월드로 나누는 방식이 있다.
채널(channel)로 쪼개기
- 채널은 하나의 월드(세계) 안에서 같은 맵을 동시에 여러 인스턴스로 실행하는 구조로, DB는 공유되지만 서로 다른 채널에 존재하는 유저들은 마주칠 수 없는 방식이다.
- 각각의 채널들은 서로 다른 서버에서 돌아가며, 각 서버는 논리적 서버이든, 물리적 서버이든 상관없기 때문에, 인기가 없는 채널(보통 맨 뒤에 있는 채널)의 경우 하나의 물리적 서버에서 처리하는 경우도 있다.
- (근데, 이렇게 물리적 서버, 논리적 서버를 나누는 것이 큰 의미가 없는 게, 채널을 쪼갤 정도로 고려하는 상황이 오면 AWS를 쓰는 상황일 텐데, 우리가 AWS에서 서버를 빌린다는 건 논리적 서버를 빌린다는 것이다. 그렇기 때문에 물리적 서버를 고려해서 2개의 채널을 맡기고 하는 부분은 생각하지 않아도 된다.)
-----------World-------------------------------------
| <Ch1. [마을1]-[늪지1]-[초원1] > |
| <Ch2. [마을2]-[늪지2]-[초원2] > <===> GameDB |
| <Ch3. [마을3]-[늪지3]-[초원3] > |
| <... > |
-----------------------------------------------------
- 하나의 서버가 수용할 수 있는 유저수가 1000명이었다면, 채널을 활용했을 경우, 1000*N의 유저를 수용할 수 있게 된다. 따라서, 채널을 10개만 판다면 원했던 10,000명의 유저를 받을 수 있게 되는 것이다.
- 채널의 특징은 다른 채널로 쉽게 넘어갈 수 있다는 것이다. 만약, 현재 채널의 사람이 너무 많아서 마땅한 사냥터가 없다면 한적한 채널로 넘어가서 쾌적한 사냥터 사냥을 즐길 수 있게 된다.
- 채널을 넘어가는 것은 즉슨, 다른 논리적 서버로 넘어간다는 것을 의미한다. 이에 필요한 정보는 공용 컴포넌트 역할로 redis를 박아놓고 활용할 수 있다.
채널 방식의 장점
- 서버에 장애가 와도, 장애가 발생하지 않은 다른 채널로 넘어가면 된다.
- 수평적 확장을 하는 데 있어 용이하다
채널 방식의 단점
- 같은 필드에 상대적으로 적은 유저수만 받을 수 있다.
- 월드 보스 이벤트를 하기 어려워진다.
존(zone)으로 쪼개기
- 채널 방식의 문제점은 하나의 필드에 사람이 몰리면, 서버의 부하를 못 버틸 수 있다는 것이다. 서버가 동접 인원 3000명 받을 수 있다는 말이 한 필드에 유저들이 우글우글 모여있을 때를 상정하진 않기 때문이다. 그래서 채널 방식으로 “서버를 쪼개는 것은 한 필드에 많은 유저를 받지 못한다”는 단점이 있다.
- 그래서 한 필드에 수백 명의 유저가 있어도 거뜬히 유지할 수 있는 분산 서버 방식을 원한다면, 존으로 쪼개는 방식이 있다.
- 존으로 쪼개는 방식은 필드 단위로 서버를 배치하는 것으로, 이 경우, 하나의 서버가 하나의 존만 처리하기 때문에 서버의 모든 성능을 하나의 존에 전부 끌어다 쓸 수 있다.
-----------World-------------------------------------
| <[----------마을-------------]> |
| <[----------늪지-------------]> <===> GameDB |
| <[----------초원-------------]> |
| <... > |
-----------------------------------------------------
존 방식의 장점
- 개발 시 존의 확장이 굉장히 쉬워진다. (존마다 프로그램이 분리되기 때문)
- 월드 보스 이벤트 등, 월드 단위 이벤트를 하기 쉽다.
- 같은 필드(존)에 상대적으로 많은 유저수를 받을 수 있다.
존 방식의 단점
- SPOF 발생 우려 - 특정 존을 담당하는 서버가 터지면, 해당 존은 접근할 수 없게 된다.
- 수평적 확장을 하는 데 있어 불리하다.(이쯤 되면 월드를 새로 파야한다.)
월드 단위로 쪼개기
- 채널과 존 방식의 서버 쪼개기 방식과 다르게 월드 단위로 서버를 쪼개는 것은 조금 의미가 다르다. 앞서본 두 방식은 같은 월드를 공유하고 있기 때문에 언제든지 접속한 다른 유저를 만날 수 있는 기회가 있었다면, 월드 단위로 쪼개는 것은 완전히 독립적으로 운영되기 때문에(gameDB도 다르다), 서로 다른 월드에 존재하는 유저끼리는 죽었다 깨어나도 만날 수 없다.
- 보통 월드 단위로 쪼개는 이유는 다양한데 대표적인 이유는,
- 유저 분산: 같은 월드에서 서버를 더 쪼개는 데 어려운 경우. (DB 쪽은 샤딩의 한계나 기획 쪽은 유저 분산으로 인한 랭킹전 경쟁 스트레스 완화)
- 독립적인 운영: 글로벌 서버 운영 및 서로 다른 버전 운영 + 테스트 서버 등등…