게임 통신 프로토콜 - geim tongsin peulotokol

멀티플레이 게임이 성행하고 게임의 이용자수가 많아지면서 유저들을 연결하는 서버의 역할이 중요해졌다. 게임을 이용하는 유저가 많아질수록 서버가 짧은 시간에 처리해야 하는 데이터의 양은 기하급수적으로 상승하는데, 이 말은 즉 데이터 처리 속도가 매우 중요하다는 것이다. 이를 위해 게임 서버에는 다양한 기술이 사용된다.

· 네트워크 프로토콜

컴퓨터 네트워크를 배우면 마주하는 OSI 7 Layers와 같은 네트워크 프로토콜 계층에서 여러 프로토콜을 마주할 수 있다. 게임 서버에서 중요하게 다루는 프로토콜은 보통 TCP/UDP이다.

- TCP

  • TCP(Transmission Control Protocol)는 쉽게 '패킷에 대한 신뢰성을 보장'해주는 프로토콜이라고 보면 된다. 네트워크는 유무선으로 연결되어 유선인 경우 선 또는 라우터와 같은 장비에 문제가 생기면, 무선인 경우 전파를 송수신하는 기기에 문제가 생기면 네트워크를 건너는 패킷이 유실되거나 손상될 수 있다.

    처음 송수신할 소켓끼리 연결 가능한 상태인지, 송수신할 대상이 맞는지에 대한 패킷을 주고받으며, 송신하는 패킷은 상대방이 확실히 받아야 하는 내용들이므로 Packet loss가 발생하지 않도록 송신 측에선 패킷을 보내고 수신 측에서 정상적으로 패킷을 받았다는 신호를 받기 전까지 보낸 패킷을 버퍼에서 비우지 않고 유지한다. 이러한 소켓끼리의 연결 확인, 송신 보장, 패킷 순서 보장 등의 기능을 제공한다.

- UDP

  • UDP(User Datagram Protocol)는 데이터를 빠르게 주고받는 데에 최적화된 프로토콜로, 앞선 TCP의 연결 확인, 송신 보장, 패킷 순서 보장을 지원하지 않는다. 하지만, 신뢰성을 보장하기 위해 일련의 확인 과정을 거칠 필요가 없기 때문에 TCP보다 훨씬 빠른 통신 속도를 보장한다.

- Reliable UDP

  • Reliable UDP는 신뢰성이 보장되는 UDP로, 물론 프레임 단위 시간 차이로 승부가 갈릴 수 있는 게임에서 속도가 매우 중요하겠지만, 그만큼 정확한 것도 중요하다. 따라서 TCP가 패킷에 대한 신뢰성을 보장하는 기능 중 필요한 것들만 챙기고 불필요한 것들은 배제하여 UDP에 적용한 커스텀 프로토콜을 게임 서버에 구현해 사용하곤 한다.

어떤 프로토콜을 선택할지는 게임의 규모, 장르, 개발자의 역량에 따라 다르다. 매우 정확한 타이밍이 중요한 격투, FPS, AOS 등의 장르에선 Reliable UDP가 유리할 것이고, MMORPG와 같이 어느 정도의 오차는 감수할 수 있는 장르는 TCP를 활용하는 것이 유리할 것이다.

Reliable UDP가 TCP의 장점을 일부 가지긴 하지만 AAA 게임이나 커다란 기업에서의 기술력으로는 Reliable UDP를 구현하여 게임에 적용할 수 있지만, 패킷 로스에 대한 방어 로직을 추가하고 흐름 제어나 혼잡 제어를 TCP만큼 확실하게 설계하는 것은 일반적으로 결코 쉽지 않기 때문이다.

TCP에는 헤더에 비해 실제로 전송할 데이터가 너무 작을 때 좀 더 효율적으로 패킷을 보내도록 일정한 규칙에 따라 패킷 전송을 지연하고 한 번에 전송하는 Nagle algorithm이 적용되어 있는데, 이 설정을 끄는 것만으로도 꽤나 즉각적인 정보 교환이 가능하기 때문에 이러한 방식으로 실시간 게임에 적용할 수도 있다.

· 멀티스레딩

현대의 기술로는 하나의 코어가 연산을 빠르게 할 수 있는 최대치에 다다랐다. 더 빠르게 만들 방법은 있지만 이로 인해 발생하는 열을 잡을 방법이 없어 코어를 더 빠르게 하는 것은 무리가 있다.

이를 위해 개발된 것이 멀티스레딩, 혹은 하이퍼스레딩이라 불리는 기술이다. 게임이 실행되면서 수많은 오브젝트가 동시에 렌더링, 애니메이션, 물리, 오디오 등 다양한 요소를 업데이트해야 하는데, 이것을 적절히 분배하여 빠르게 처리해주는 것이다.

- Heterogeneous 멀티스레딩

  • 초창기에 많이 사용한 멀티스레딩 방식으로, 스레드마다 하는 역할이 다르다.

    앞서 말한 렌더링, 애니메이션, 물리 등의 작업마다 스레드를 할당하는데, 게임에 존재하는 오브젝트는 자신에게 적용되는 물리 계산이 끝난 것에 따라 메시의 본을 움직여 애니메이션을 업데이트하고, 결정된 내용에 따라 렌더링을 한다. 즉, 이전 순서가 마무리되지 않으면 다음 순서가 실행될 수 없는 것이다.

    작업마다 처리 속도가 다르기 때문에 애니메이션 처리를 아무리 빨리 할 수 있더라도 물리 계산이 느리면 애니메이션 스레드는 아무 것도 하지 못하고 기다릴 수밖에 없다. 마찬가지로 렌더링도 이루어질 수 없다. 특정 작업만을 위한 스레드이므로 일이 많은 스레드에서 일을 받아오는 것도 매우 어려운 일이다. 이러한 이유로 병렬성이 제한되는 멀티스레딩 방식이다.

- Homogeneous 멀티스레딩

  • 현존하는 대부분 프레임워크가 채택하는 멀티스레딩 방식이다. 스레드는 모두 같은 역할을 한다.

    앞선 방식과의 차이는 쉽게 말해서 한 스레드가 맡는 작업량을 작업 종류가 아닌 오브젝트로 나누는 것이다. 일반적으로 스레드는 처리해야 하는 오브젝트보다 훨씬 적은 갯수인데, 오브젝트를 적절하게 스레드에 분배하여 하나의 스레드가 여러 오브젝트를 처리하게 한다.

    게임 통신 프로토콜 - geim tongsin peulotokol

    그리고 해야하는 일들을 순서에 맞게 실행하는 것이다. 모든 오브젝트에 가장 먼저 해야 하는 작업을 먼저 처리해주고 일이 다 끝나면 다음 작업을 수행한다. 오브젝트에 따라 조금 빠르게 끝난다고 하더라도 먼저 넘어가지 않고 기다린다.

    이렇게 마냥 기다리는 것이 다소 비효율적일 수 있기 때문에 자신의 할당량을 빠르게 마친 스레드에서 아직 일이 많은 스레드의 일을 가져와 대신 수행해주는 Job Stealing과 같은 기술이 추가로 도입되기도 하였다.

    이러한 형태의 멀티스레딩 방식을 Task system이라고도 부른다.

· Client-Server 구조

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 동기화 기술

개요

늘 궁금했다. 웹 개발이란 어떤 것인지.

물론 이것저것 관심이 많다 보니, 임베디드, 보안, 인공지능 등 대부분 관심이 많지만, 좀 더 대중화 되고 컨텐츠 개발에서 주류에 있는 웹개발은 조금 더 궁금했다.

사실상 책 따라하기 수준의 방명록, 게시판 정도론 웹 개발자들이 어떻게 생각하고, 무엇을 중요시 여기고, 어떤 것을 잘해야 하고, 어떻게 일하는지 알 수 없었다.

그저 짐작을 할 뿐이나, 웹알못이 짐작하는 수준이라곤 게임 서버도 보이지 않는 backend 관점이니, 웹 백엔드와 큰 차이가 없을거라고 생각했다.

결론부터 말하자면, 비슷하면서도 아주 많은 간극을 보인다.

특히 문제를 해결하는 방법, 중요시 여기는 가치, 기본기라 여기는 기준들 너무 많은 것이 달랐다.

약간 과장해서, 다른 직업이라고 느껴질 정도로 달랐다. (과장이라고 표현했으나 나는 이렇게 생각하고 있다. 임베디드, 웹, 보안, 플랫폼, 게임 등…각 분야가 의외로 많은 차이를 보인다고 생각한다.)

고찰

왜 이런 차이가 생기는 걸까?

웹의 발전은 브라우저 기반위에서 이루어졌다.

브라우저라함은 HTML 파서이자 뷰어라 할 수 있는데, 브라우저가 소화 가능한 규격으로만 통신해야 함을 의미한다.

이를 주고 받기 위한 HTTP 프로토콜이 반론의 여지가 없는 표준이었다. 웹표준과 별개로 HTTP 프로토콜은 웹에선 빠르고, 당연하게 표준으로 자리 잡았다.

초창기 성능이나 네트웍 속도에 제약으로, 정적 페이지를 적극 사용했는데, 이는 소수의 관리자가 컨텐츠를 편집했기에 가능한 접근이었다.

반면 게임 서버는 커스텀한 클라이언트 프로그램인 게임을 위해 발전해왔다. 브라우저라는 제약이 없었고, 그러므로 반드시 HTTP 프로토콜을 사용할 필요는 없었다. 그렇다 보니, HTTP 프로토콜에서 소요되는 cost마저 아끼고 싶어했다. (소켓을 직접 통제하고, 헤더와 인증, 보안 처리 모두 커스텀하게 처리했음을 말한다.)

또한 HTTP 프로토콜의 특징인 connectionless, stateless는 게임에 어울리지 않았다.

이는 아래서 설명할 반응성이 웹보다 훨씬 중요하기 때문이다.


차이

당시에도 그랬고, 지금도 게임은 반응성이 웹보다 훨씬 더 중요한 분야다. connection을 맺고 끊는 비용, connection이 생성되고 필요한 작업을 위해 매번 db를 질의하는 비용 모두 줄여서라도 반응성을 유지하는 것이 더 중요했다.

그렇다보니 표준이 아닌, 게임 마다 다른 TCP 프로토콜 위에 게임별 프로토콜이 각기 다른 모습으로 구현됐다.

동적 컨텐츠인 게임은, 웹처럼 다수의 사용자에게 유사한 HTML 코드를 동일하게 전송할 수 없었고, 실시간으로 변동되는 데이터를 다뤄야했기에, 다른 방향으로 발전했다.

요새의 게임 개발에선 아닌 경우가 더 많아 졌지만, 내가 처음 게임 개발에 입문했을 때만해도, 패킷 만들 때 최소한의 비트를 사용하고, 어셈코드로 렌더링하며, 메모리 정렬 단위를 계산하며, 복사 연산을 최소화 하기 위한 코딩을 했어야 했다.

이는 제한된 서버 자원을 잘 활용해야만 동접이 높은 게임을 만들 수 있기 때문이다. 그 게임 내에서 수많은 동작이 실시간으로 이루어지는데, 이 로직들을 최대한 가볍게 짜고, 의도치 않은 큰 연산이 일어나지 않아야 렉이 생기지 않기 때문이다.

실제로 온라인 게임의 렉(latency)은 대부분 네트워크 환경으로 인한 문제보다는 서버 내부의 로직이 도는 시간보다 더 많은 처리 요청이 발생해 처리가 밀리면서 발생한 현상이었다. 멀티스레드로 구현하면서, 블러킹 포인트를 만들어 생기는 경우도 없었다고 할순 없겠다.

이는 패킷을 처리하고, 사용자에게 응답하기 까지의 시간을 유지하지 못하면 응답성이 떨어지며, 이 응답성이 게임 클라이언트가 허용한 범주보다 늦어지게 되면 사용자는 렉을 느끼게 된다. 이를 해결하는 방향성 중 하나는 모든 연산을 최저치로 낮출 수 있는 데로 낮추는 접근이었다고 말할 수 있겠다.

게임에서는 반응속도와 함께, 데이터 무결성을 보장해주어야 한다. 게임 사용자는 조금의 지연도 용납해주지 않는다.

내가 조금전 획득한 아이템이 10초후에 인벤토리에 들어온다고 치자. 사용자들은 바로 불편함과 우려를 표할 것이다. 아이템 시스템에 오류가 생긴것이 아닐까 불안해하며, 자신이 획득할 아이템에 대한 신뢰도마저 의심하곤 한다.

마찬가지로, 내가 싸우는 몬스터의 HP 감소가 10초후에 이루어진다면? 내 체력도 10초후에 감소 된다면? 사용자들은 해당 게임이 정상적이지 않고, 문제가 있다고 인지하는 상황이 된다.

그리고 만약 재접속 해야만 아이템 보상이 들어온다면? 현재 내 아이템 상황과, 내 눈에 보이는 상황이 달랐을 때 사용자들은 이 상황을 문제라고 인지하게 된다. 아마도 디아블로2의 복사 아이템 사건등을 겪은 사용자들이, 이런 현상이 아이템 복사 등으로 이어질지 모른다는 불안감도 한몫 해서 불안함을 갖기도 한다.

지연적인 아이템, 상태 반영이 해당 게임의 시스템적으로 구성되어있다면, 불편함과 비직관성으로 큰 비판을 받게될 요소다.


반면 웹은 실제 디비에서 처리되고 있는 데이터보다 조금 예전 데이터를 주더라도 크게 문제 삼지 않는다.

그렇다보니 캐싱이 더 쉬워지고, 브라우저도 캐싱을 하며, 사용자도 이를 인정하고 새로운 데이터를 전달 받기 위해 새로고침을 직접 한다. (사용자들 마저 이 과정을 불쾌감으로, 오류로 받아들이지 않고 자연스럽게 받아들이는 것이 포인트다.)

이는 훨씬 더 많은 사용자에게 컨텐츠를 제공하는 방향으로 발전할 수 있는 원동력이 되기도 했다. 캐싱과 스케일아웃이 유연할 수 있는 근거는, 지금 언급한 조금의 지연이 있는 데이터, 혹은 소수의 사용자가 편집한 데이터를 전달하는 것도 용인 될 수 있는 웹 환경이 그 근거다.

애초에 데이터의 변화량/응답속도가 너무나도 중요한 가치인 게임과, 생산성/확장성이 더 중요한 웹은 궤를 달리 할 수 밖에 없었던 운명이었던 걸지도 모른다.

이제와서 서로 간의 기술 융합과 응용이 이루어지고 있는 모습은 아주 긍정적이라고 생각한다. 이 흐름이 상대적으로 서버의 역할을 한정 지었던 모바일 게임에서의 웹 서버 기반의 서비스였긴 하지만, 그렇게 많은 게임 서버 개발자들이 웹 이해도가 늘었다.


마치며

다시금 모바일 게임도 MMORPG붐이 일면서, C++, C# TCP 게임 서버가 다시금 도입되고 있다. 최근 몇년간 게임 개발을 하고 있지 않아서 정확히 말하긴 어렵지만, 커스텀 게임 서버만으로 모든 컨텐츠를 만들어오던 과거와는 달리 이제는 적절한 지점에 웹서버도 이용하지 않을까 싶은 생각도 든다.

트랜잭션 위주의 로직 서버로 웹 서버는 탁월한 선택이 될 수 있다. 또한 인게임 컨텐츠 중 일부(예를 들어 인게임 공략, 공지사항, 상점, 광고, 일부 이벤트 등)의 경우 웹 서버를 통해 구현하면 훨씬 더 수월하게 구현 가능하기도 하다.

또한, 게임마다 다른 내부 구조를 이해하지 않고도, 사용되는 웹 프레임워크만 이해하는 사람도, 부분적인 분업도 가능해지므로 이 또한 협업과 분업의 메리트가 생길 수 있는 부분이다.

또한 성능상의 이슈에서 상대적으로 자유로울 수 있는 컨텐츠 위주로 웹 서버를 이용한다면, 생산성 좋은 언어, 프레임워크를 선정할 수 있다는 장점도 있다.

그렇게 유연한 선택을 통해, 안정성과 생산성을 얻을 수 있다면, 좀 더 고민이 많이 필요하고, 시간이 많이 필요한 작업에서 필요한 시간을 버는 데에 쓸 수 있을 것이다.

게임 서버는 특수성으로 인해 웹서버만으로 모든 시스템을 구축/운용 하는 것도 안되고, 커스텀 TCP 서버는 생산성이 너무 떨어진다. 이제는 게임 서버 개발에서도 폴리글랏 아키텍쳐가 필요할 때가 아닐까?