멀티플레이 게임이 성행하고 게임의 이용자수가 많아지면서 유저들을 연결하는 서버의 역할이 중요해졌다. 게임을 이용하는 유저가 많아질수록 서버가 짧은 시간에 처리해야 하는 데이터의 양은 기하급수적으로 상승하는데, 이 말은 즉 데이터 처리 속도가 매우 중요하다는 것이다. 이를 위해 게임 서버에는 다양한 기술이 사용된다.
컴퓨터 네트워크를 배우면 마주하는 OSI 7 Layers와 같은 네트워크 프로토콜 계층에서 여러 프로토콜을 마주할 수 있다. 게임 서버에서 중요하게 다루는 프로토콜은 보통 TCP/UDP이다.
TCP(Transmission Control Protocol)는 쉽게 '패킷에 대한 신뢰성을 보장'해주는 프로토콜이라고 보면 된다. 네트워크는 유무선으로 연결되어 유선인 경우 선 또는 라우터와 같은 장비에 문제가 생기면, 무선인 경우 전파를 송수신하는 기기에 문제가 생기면 네트워크를 건너는 패킷이 유실되거나 손상될 수 있다.
처음 송수신할 소켓끼리 연결 가능한 상태인지, 송수신할 대상이 맞는지에 대한 패킷을 주고받으며, 송신하는 패킷은 상대방이 확실히 받아야 하는 내용들이므로 Packet loss가 발생하지 않도록 송신 측에선 패킷을 보내고 수신 측에서 정상적으로 패킷을 받았다는 신호를 받기 전까지 보낸 패킷을 버퍼에서 비우지 않고 유지한다. 이러한 소켓끼리의 연결 확인, 송신 보장, 패킷 순서 보장 등의 기능을 제공한다.
어떤 프로토콜을 선택할지는 게임의 규모, 장르, 개발자의 역량에 따라 다르다. 매우 정확한 타이밍이 중요한 격투, FPS, AOS 등의 장르에선 Reliable UDP가 유리할 것이고, MMORPG와 같이 어느 정도의 오차는 감수할 수 있는 장르는 TCP를 활용하는 것이 유리할 것이다.
Reliable UDP가 TCP의 장점을 일부 가지긴 하지만 AAA 게임이나 커다란 기업에서의 기술력으로는 Reliable UDP를 구현하여 게임에 적용할 수 있지만, 패킷 로스에 대한 방어 로직을 추가하고 흐름 제어나 혼잡 제어를 TCP만큼 확실하게 설계하는 것은 일반적으로 결코 쉽지 않기 때문이다.
TCP에는 헤더에 비해 실제로 전송할 데이터가 너무 작을 때 좀 더 효율적으로 패킷을 보내도록 일정한 규칙에 따라 패킷 전송을 지연하고 한 번에 전송하는 Nagle algorithm이 적용되어 있는데, 이 설정을 끄는 것만으로도 꽤나 즉각적인 정보 교환이 가능하기 때문에 이러한 방식으로 실시간 게임에 적용할 수도 있다.
현대의 기술로는 하나의 코어가 연산을 빠르게 할 수 있는 최대치에 다다랐다. 더 빠르게 만들 방법은 있지만 이로 인해 발생하는 열을 잡을 방법이 없어 코어를 더 빠르게 하는 것은 무리가 있다.
이를 위해 개발된 것이 멀티스레딩, 혹은 하이퍼스레딩이라 불리는 기술이다. 게임이 실행되면서 수많은 오브젝트가 동시에 렌더링, 애니메이션, 물리, 오디오 등 다양한 요소를 업데이트해야 하는데, 이것을 적절히 분배하여 빠르게 처리해주는 것이다.
초창기에 많이 사용한 멀티스레딩 방식으로, 스레드마다 하는 역할이 다르다.
앞서 말한 렌더링, 애니메이션, 물리 등의 작업마다 스레드를 할당하는데, 게임에 존재하는 오브젝트는 자신에게 적용되는 물리 계산이 끝난 것에 따라 메시의 본을 움직여 애니메이션을 업데이트하고, 결정된 내용에 따라 렌더링을 한다. 즉, 이전 순서가 마무리되지 않으면 다음 순서가 실행될 수 없는 것이다.
작업마다 처리 속도가 다르기 때문에 애니메이션 처리를 아무리 빨리 할 수 있더라도 물리 계산이 느리면 애니메이션 스레드는 아무 것도 하지 못하고 기다릴 수밖에 없다. 마찬가지로 렌더링도 이루어질 수 없다. 특정 작업만을 위한 스레드이므로 일이 많은 스레드에서 일을 받아오는 것도 매우 어려운 일이다. 이러한 이유로 병렬성이 제한되는 멀티스레딩 방식이다.
현존하는 대부분 프레임워크가 채택하는 멀티스레딩 방식이다. 스레드는 모두 같은 역할을 한다.
앞선 방식과의 차이는 쉽게 말해서 한 스레드가 맡는 작업량을 작업 종류가 아닌 오브젝트로 나누는 것이다. 일반적으로 스레드는 처리해야 하는 오브젝트보다 훨씬 적은 갯수인데, 오브젝트를 적절하게 스레드에 분배하여 하나의 스레드가 여러 오브젝트를 처리하게 한다.
그리고 해야하는 일들을 순서에 맞게 실행하는 것이다. 모든 오브젝트에 가장 먼저 해야 하는 작업을 먼저 처리해주고 일이 다 끝나면 다음 작업을 수행한다. 오브젝트에 따라 조금 빠르게 끝난다고 하더라도 먼저 넘어가지 않고 기다린다.
이렇게 마냥 기다리는 것이 다소 비효율적일 수 있기 때문에 자신의 할당량을 빠르게 마친 스레드에서 아직 일이 많은 스레드의 일을 가져와 대신 수행해주는 Job Stealing과 같은 기술이 추가로 도입되기도 하였다.
이러한 형태의 멀티스레딩 방식을 Task system이라고도 부른다.
C/S 구조라고도 부르며, 중앙인 서버의 도움을 받아 사용자인 클라이언트끼리의 통신을 돕는 구조이다. 또 다른 서버 구조로는 P2P(Peer to Peer) 구조가 있는데, 이는 클라이언트끼리 직접 통신하는 방식이어서 빠른 속도를 보장하지만, 통신하는 사용자가 핵 등의 프로그램으로 데이터를 변조하여 보내는 것을 막기가 어려워 요즘은 P2P보다 C/S 구조를 선호한다.
C/S 구조는 서버가 반드시 존재하고, 사용 가능한 상태여야 한다. 각 클라이언트는 서버에 접근하여 연결 요청을 하고, 이것이 받아들여졌을 때부터 접속하여 실제 통신이 가능하다.
서버가 있기 때문에 동기화나 일관성 있는 결과 처리에 수월하고, 악의적으로 게임 데이터를 손상하거나 핵을 사용하는 것에 대한 조치가 쉽다.
하지만 그만큼 로직 구현이 어려워 기술 개발과 비용이 많이 필요하며, 필요한 데이터가 항상 서버를 거쳐가므로 지연 시간(Latency)이 발생하게 된다. 이러한 지연 시간은 서버를 경유하기 때문에 통신 경로가 길어지는 것뿐 아니라 네트워크 상태가 좋지 않을 때 패킷을 올바르게 주고받지 못하면 훨씬 더 악화되기도 한다.
이러한 문제들에 대해 서버는 최악의 경우(Worst case)를 대비하는 것이 중요하다. 평소에는 완벽하지만 최악의 경우에 큰 문제가 발생할 수 있다면, 최악의 경우에 대한 처리를 개선하는 것이 더 좋은 게임일 수 있다. 예를 들어 MMORPG 게임의 핑이 100ms일 땐 이동 명령이 정확한 움직임을 보이지만, 200ms일 때 이동하다가 멈추는 명령을 내리면 지연에 의해 최종 위치가 달라진다고 하자. 이 경우 일반적인 핑에서도 마치 200ms의 환경에서 명령을 받는 것처럼 꾸미고 명령에 대한 보정을 강하게 처리해주면 보정을 할 수 없을 정도의 케이스는 없다고 할 수 있는 수준이 될 수 있다.
▶ 캐릭터 이동 동기화 방법
▶ 네트워크 게임 서버는 TCP? UDP?
▶ Homogeneous 멀티스레딩 이미지 출처 - 포프TV "바람직한 멀티스레딩 구조" 영상
▶ 온라인 게임 P2P, C/S 구조
▶ NDC 실시간 MMORPG 동기화 기술