게임 서버 아키텍처

아직 작성중입니다.


게임 서버 아키텍처에 관한 이야기를 합니다. 대부분의 내용은 MMORPG에 특화되어 있습니다.

게임 서버

아주 간단한 게임 서버를 생각해봅시다. 아래처럼 클라이언트와 서버가 아래와 같이 연결되어 있습니다.

flowchart LR 클라이언트1 <--> 서버 클라이언트2 <--> 서버 클라이언트3 <--> 서버

이처럼 다수의 클라이언트들이 서버를 통해서 상호작용합니다. 지금은 서버가 처리해야 할 클라이언트도 많지 않고, 사용자의 데이터를 영구적으로 저장하는 것도 고려되지 않았는데 하나씩 더 살펴봅시다.

관계형 데이터베이스 추가

서버에 관계형 데이터베이스를 추가합니다. 관계형 데이터베이스와 같은 영구적 저장소는 서버가 사용자 데이터를 계속 유지하지 않을 수 있게 해 줍니다. 만약 이러한 저장소가 없으면 서버 재시작시 모든 데이터가 소실될 것입니다. 뿐만 아니라 관계형 데이터베이스가 제공하는 트랜잭션은 서버 스스로 처리하면 매우 복잡했을 계산을 간단하게 만들어줍니다.(요즘은 이 단계에서 관계형 데이터베이스 외의 대안도 고려되지만 지금은 다루지 않습니다.)

flowchart LR 클라이언트1 <--> 서버 클라이언트2 <--> 서버 클라이언트3 <--> 서버 서버 <--> database[관계형 데이터베이스]

서버의 물리적 한계

서버 하드웨어는 놀라운 속도로 발전하고 있지만 단일 서버가 감당할 수 있는 동시접속자 수는 한계가 있습니다. 각 개발사에서 투명하게 동시접속자를 공개하고 있지 않기 때문에 정확히는 알 수 없지만 현재(2020년 8월) 기준으로 수만에 머무를 것으로 추정됩니다.

그런데 뭔가 이상하지 않나요? 게임이 아닌 서비스는 수백에서 수천만 이상의 훨씬 높은 수의 동시접속자를 감당해 내고 있습니다. 왜 게임은 겨우 수만 수준의 동시접속자만을 감당할 수 있을까요? 그 이유는 게임 서버는 상태를 가지고 있기 때문입니다. MMORPG는 사용자의 상태를 장기간 보유하고 매우 자주 바꾸는 특성이 있습니다.

스테이트리스와 스테이트풀한 서버의 분리

하지만 MMORPG라고 하더라도 모든 부분이 상태를 필요로 하지는 않습니다. 그러면 아래와 같이 구성을 해 보는 것은 어떨까요?

flowchart LR 클라이언트1 <--> stateful[스테이트풀 서버] 클라이언트2 <--> stateful[스테이트풀 서버] 클라이언트3 <--> stateful[스테이트풀 서버] 클라이언트1 <--> stateless[스테이트리스 서버] 클라이언트2 <--> stateless[스테이트리스 서버] 클라이언트3 <--> stateless[스테이트리스 서버] stateful[스테이트풀 서버] <--> database[관계형 데이터베이스] stateless[스테이트리스 서버] <--> database[관계형 데이터베이스]

사용자의 현재 능력치, 이동관련 처리나 NPC의 AI 계산 등 상태유지가 필요한 부분은 스테이트풀 서버로, 아이템의 제작, 결제 등 상태유지가 필요없는 부분은 스테이트리스 서버로 구성할 수 있습니다.

위 다이어그램에는 스테이트풀 서버와 스테이트리스 서버는 서로 통신하지 않습니다. 스테이트리스 서버의 변경사항이 스테이트 풀 서버에 영향을 줄 수도 있는데 어떻게 서로 통신하지 않을 수 있을까요? 답은 간단합니다. 클라이언트가 변경사항을 알고, 스스로가 속한 스테이트풀 서버를 알기 때문에 스테이트리스 서버 변경사항을 스테이트풀 서버에 반영요청합니다. 스테이트리스 서버과 스테이트풀 서버를 직접 통신할 수도 있겠지만 그러려먼 불필요한 관리지점이 하나 더 생깁니다.

관련 링크

홍성우, 게임 서버의 목차 - 시작부터 출시까지, NDC2019 게임서버 출시까지 고려해야 할 내용이 잘 정리되어 있습니다.

거대한 단일 MMORPG 서버 2019년 9월에 스터디에서 발표한 거대한 단일 MMORPG 서버에 대한 이야기입니다.