테마 선택

📚 지식 노트

AI·하드웨어·주변기기·게임·컴퓨터 시스템·이론 컴퓨터 과학·수학·개발과 운영·보안·응용 분야에 대해 알아 두면 좋은 내용을 정리한 노트다. 위에서 분야를 고르고 아래에서 노트를 고른다.

멀티플레이어 서버 설계

온라인 게임 서버를 어떻게 나누고 띄우고 늘리는가. 권한 서버, 전용 서버 할당, 세션형과 지속 세계, 지역과 지연을 다룬다.

목차 (8)
  1. 연결 구조 넷: 누가 판정하고 누가 중계하나
  2. 전용 서버의 한살이: 플릿, Ready, 할당, Shutdown
  3. 세션형과 지속 세계: 샤드, 구역, 인스턴스
  4. 틱 레이트와 대역폭: 얼마나 자주, 얼마나 많이
  5. 지역과 지연: 서버를 어디에 둘까
  6. 규모와 비용: 버퍼, 스팟, 그리고 업체
  7. 장애와 복구: 체크포인트와 호스트 이전
  8. 프로토콜: UDP 위에 필요한 만큼만

연결 구조 넷: 누가 판정하고 누가 중계하나

온라인 게임을 설계할 때 가장 먼저 정하는 것은 "누가 진실을 갖는가"다. 두 사람이 같은 순간 같은 상자를 집으면 누가 가졌는지, 총알이 맞았는지를 한 곳에서 판정해야 화면이 어긋나지 않는다. 판정하는 쪽과 패킷이 지나가는 길을 어떻게 놓느냐에 따라 구조가 넷으로 나뉜다. 화면이 지연을 어떻게 숨기는지(클라이언트 예측, 랙 보상, 롤백)는 게임 개발의 멀티플레이 노트에 있으니, 여기서는 그 밑의 서버 구조를 다룬다.

멀티플레이어 연결 구조 넷: 전용 서버 하나가 판정하는 클라이언트-서버, 모두가 서로 직접 보내는 P2P, 플레이어 하나가 서버를 겸하는 리슨 서버, 모든 트래픽이 중계 서버를 거치는 릴레이클라이언트-서버 (권한 서버)전용 서버플레이어 1플레이어 2플레이어 3서버만 판정하고 모두에게 알린다P2P (피어 투 피어)피어 1피어 2피어 3피어 4모두가 모두에게 직접 보낸다리슨 서버호스트: 플레이 + 서버플레이어 2플레이어 3호스트가 나가면 경기가 멈춘다릴레이 (중계 서버)릴레이피어 1피어 2피어 3피어 4IP를 숨기고 NAT를 넘는다
연결 구조 넷. 권한 서버는 서버 하나가 판정한다. P2P는 모두가 서로에게 보낸다. 리슨 서버는 플레이어 하나가 서버를 겸한다. 릴레이는 판정 없이 패킷만 중계해 IP를 숨기고 NAT를 넘는다.
  • 클라이언트-서버(권한 서버): 회사가 띄운 전용 서버(dedicated server)가 게임 상태의 유일한 원본이다. 클라이언트는 입력만 보내고 서버가 결과를 정해 돌려준다. 클라이언트를 고쳐도 서버가 받아 주지 않으니 치트에 강하고, 누가 나가도 경기가 이어진다. 대가는 서버 비용과 운영이다. 경쟁 FPS·배틀로얄·MOBA 대부분이 이 구조다.
  • P2P: 서버 없이 플레이어끼리 직접 주고받는다. 서버비가 들지 않고 가까운 두 사람은 지연이 가장 짧다. 그러나 판정할 곳이 없어 모두가 같은 계산을 하는 결정적 락스텝이나 롤백을 써야 하고, 연결 수가 사람 수의 제곱으로 늘며, 상대에게 내 IP가 드러난다. 격투 게임과 소규모 협동 게임이 주로 쓴다.
  • 리슨 서버: 플레이어 하나(호스트)가 게임을 하면서 서버 역할도 한다. 서버비는 없지만 호스트가 지연 0으로 유리하고, 호스트가 치트를 쓰면 막을 수 없으며, 호스트가 나가면 경기가 멈춘다(아래 "호스트 이전"). 친구끼리 하는 협동 게임에 흔하다.
  • 릴레이: P2P나 리슨 서버의 패킷을 중계 서버가 대신 전달한다. 판정은 하지 않고 길만 놓는다. NAT 뒤라 직접 연결이 안 되는 사람도 이어 주고, 서로의 IP를 숨겨 디도스를 막는다. Valve의 Steam Datagram Relay 문서는 P2P와 전용 서버 트래픽을 Valve의 중계망으로 싣고 IP를 드러내지 않는다고 설명한다. Unity도 전용 서버 없이 플레이어를 잇는 Relay를 Multiplayer Services SDK 문서에서 Lobby·Matchmaker와 함께 묶어 제공한다.

실제 게임은 섞어 쓴다. 판정은 전용 서버가 하되 음성 채팅만 P2P로 보내거나, 협동 게임을 리슨 서버로 돌리면서 연결은 릴레이를 거치게 하는 식이다. 이 노트의 나머지는 가장 손이 많이 가는 전용 서버 구조를 중심으로 본다.

전용 서버의 한살이: 플릿, Ready, 할당, Shutdown

세션형 게임의 전용 서버는 웹 서버와 성격이 다르다. 웹 서버는 요청 하나를 아무 서버나 처리해도 되지만, 게임 서버 프로세스 하나는 경기 하나의 상태를 메모리에 들고 수십 분 동안 그 경기만 돌린다. 경기 도중 이 프로세스를 죽이면 열 명의 경기가 날아간다. 그래서 일반 오토스케일러처럼 "부하가 줄면 아무 서버나 끈다"가 통하지 않고, 서버마다 지금 경기 중인지를 아는 전용 관리 계층이 필요하다.

쿠버네티스 위에서 이 일을 하는 오픈 소스가 Agones이고, AWS의 관리형 서비스가 Amazon GameLift Servers다(2025년에 Amazon GameLift에서 이름이 바뀌었다). 둘은 용어만 다르고 같은 고리를 돈다. Agones 클라이언트 SDK 문서는 서버가 SDK로 Ready·Allocate·Shutdown을 알리고 Health 신호가 끊기면 Unhealthy가 된다고 적는다. GameLift Servers의 동작 설명도 서버 프로세스가 준비를 알리고, 배치 시스템이 경기를 맡기면 세션을 시작하고, 끝나면 스스로 내려가는 흐름을 그린다.

전용 서버 한살이 단계 그림: 플릿이 서버를 띄우면 서버가 Ready를 알리고, 매치메이커의 할당 요청으로 Allocated가 되어 플레이어가 접속하며, 경기가 끝나면 Shutdown으로 지워진다. 오토스케일러가 Ready 버퍼를 채운다매치메이커경기 묶고 서버 요청플레이어 10명플릿 (서버 빌드 하나)오토스케일러: Ready 4대 유지서버 0시작 중서버 1시작 중서버 2시작 중서버 3시작 중서버 4빈 자리플릿 = 같은 빌드의 서버 묶음 (예: replicas 4)서버 0Ready서버 1Ready서버 2Ready서버 3Ready서버 4빈 자리Agones: SDK.Ready() · GameLift: ProcessReady()서버 0Allocated서버 1Ready서버 2Ready서버 3Ready서버 4시작 중Agones: GameServerAllocation · GameLift: OnStartGameSession서버 0경기 중서버 1Ready서버 2Ready서버 3Ready서버 4ReadyGameLift: ActivateGameSession() 뒤 플레이어가 직접 접속서버 0Shutdown서버 1Ready서버 2Ready서버 3Ready서버 4ReadyAgones: SDK.Shutdown() · GameLift: ProcessEnding()서버 0빈 자리서버 1Ready서버 2Ready서버 3Ready서버 4Ready오토스케일러가 Ready 버퍼를 4대로 유지한다
1 / 6

플릿이 같은 서버 빌드를 4개 띄운다. 프로세스가 맵과 에셋을 읽는 동안은 아직 손님을 받을 수 없다.

전용 서버의 한살이. 서버는 경기 하나를 위해 태어나 Ready로 기다리고, 할당되어 경기를 치른 뒤 사라진다. 플릿은 늘 몇 대를 미리 띄워 둔다.
  • 플릿(fleet): 같은 서버 빌드를 돌리는 서버 묶음이다. 새 빌드를 올리면 새 플릿을 띄우고, 옛 플릿은 새 할당을 받지 않은 채 경기 중인 서버가 다 끝나면 사라진다. 경기를 끊지 않는 배포다.
  • 할당(allocation): 매치메이커가 "서버 하나 달라"고 하면 Ready인 서버 하나를 골라 Allocated로 바꾸고 주소를 돌려준다. 여러 매치메이커가 동시에 같은 서버를 집지 않도록 이 전환은 원자적이어야 한다. Allocated 서버는 축소나 빌드 교체 때도 지우지 않는다.
  • 한 프로세스 한 경기: 경기가 끝나면 서버를 재사용하기보다 지우고 새로 띄우는 편이 흔하다. 앞 경기의 남은 상태나 메모리 누수가 다음 경기로 넘어가지 않는다. 서버 기동이 느린 게임은 Ready로 되돌려 재사용하기도 한다.
  • 기기 하나에 여러 프로세스: 서버 프로세스 하나가 코어 하나도 다 쓰지 않는 게임이 많아, 기기 한 대에 프로세스를 여러 개 띄워 포트로 나눈다. 몇 개를 올릴지는 틱당 CPU 시간을 재서 정한다.

세션형과 지속 세계: 샤드, 구역, 인스턴스

경기가 끝나면 버리는 세션형 서버와 달리, MMO의 지속 세계(persistent world)는 서버가 꺼져도 세계가 남아야 한다. 캐릭터, 아이템, 땅에 떨어진 물건, 길드의 성이 데이터베이스에 저장되고, 수천~수만 명이 한 세계를 함께 쓴다. 서버 한 대로는 감당이 안 되니 세계를 나누는데, 나누는 축이 셋이다.

세션형과 지속 세계: 세션형은 경기마다 서버를 띄웠다가 끝나면 버린다. 지속 세계는 샤드 하나를 구역 서버 넷으로 나누고, 플레이어가 구역 경계를 넘으면 다음 구역 서버로 넘겨주며, 던전은 파티마다 인스턴스 사본을 따로 띄운다세션형경기 #104118분경기 #104222분경기 #10439분경기가 끝나면 서버를 버린다남는 것은 결과·전적뿐지속 세계: 샤드(렐름) 하나같은 세계 DB · 같은 사람들구역 1 서버구역 2 서버구역 3 서버구역 4 서버핸드오프인스턴스던전 사본 1던전 사본 2던전 사본 3파티마다 따로샤드 B, C…는 같은 세계의 독립 사본이라 서로 만나지 못한다
세션형은 경기마다 서버를 띄우고 버린다. 지속 세계는 샤드(같은 세계의 독립 사본) 안을 구역 서버로 나누고, 던전은 파티마다 인스턴스 사본을 띄운다. 구역 경계를 넘는 플레이어는 다음 서버로 넘겨준다.
  • 샤드(shard, 렐름·월드·서버라고도 부른다): 같은 세계를 통째로 여러 벌 띄우고 사람을 나눠 담는다. 샤드끼리는 데이터베이스까지 따로라 서로 만나지 못한다. 가장 쉽게 늘리는 법이지만 친구가 다른 샤드에 있으면 함께 놀 수 없고, 인구가 줄면 샤드를 합쳐야 한다.
  • 구역(zone): 한 샤드의 지도를 땅 단위로 잘라 서버마다 맡긴다. 플레이어가 경계를 넘으면 지금 서버가 캐릭터 상태를 다음 서버에 넘기는 핸드오프를 한다. 로딩 화면으로 끊으면 쉽고, 끊김 없이(seamless) 넘기려면 경계 양쪽 서버가 서로의 근처 개체를 보여 주고 넘기는 순간의 공격·이동을 맞춰야 해 어렵다.
  • 인스턴스(instance): 던전이나 전장처럼 정해진 사람만 들어가는 공간은 파티마다 사본을 띄운다. 사실상 지속 세계 안에 박힌 세션형 서버다. 붐비는 마을을 여러 사본(채널·레이어)으로 나누는 것도 같은 생각이다.

반대 방향의 유명한 예가 EVE Online이다. 전 세계 플레이어가 샤드 하나(Tranquility)를 함께 쓰고, 성계(solar system) 하나를 서버 노드 하나에 올린다. 성계 하나에 수천 척이 몰리면 그 노드의 CPU가 모자라는데, 성계를 더 쪼갤 수는 없다. CCP는 그 노드의 게임 시간만 느리게 흐르게 해 명령 대기열이 넘치지 않게 하는 길을 골랐다. 2011년 시간 늦추기(TiDi) 개발 블로그가 이를 소개했고, 정상 속도의 10%까지 늦춘다. 서버를 늘릴 수 없을 때 공정함을 지키려고 시간을 늦춘 셈이다.

세계를 공간 단위로 잘게 나눠 여러 서버(worker)에 나눠 맡기고 경계를 자동으로 옮기려 한 시도도 있었다. Improbable의 SpatialOS가 대표적이었는데, 이를 쓴 MMO 몇 편이 문을 닫거나 개발이 취소됐고 회사는 이후 다른 사업에 집중했다. 공간 분할은 개체가 한곳에 몰리면(큰 전투) 결국 한 서버가 그 지점을 맡아야 한다는 문제를 피하기 어렵고, 경계를 넘나드는 상호작용이 많을수록 서버 사이 통신이 늘어난다. 지금 대부분의 MMO는 샤드·구역·인스턴스를 섞는 쪽에 머문다.

틱 레이트와 대역폭: 얼마나 자주, 얼마나 많이

서버는 고정 간격으로 입력을 모아 세계를 한 걸음 진행하고(틱), 결과 스냅샷을 클라이언트에 보낸다. 틱 레이트가 64면 틱 하나에 쓸 수 있는 시간이 15.625ms, 20이면 50ms다. 이 예산 안에 물리, 판정, 직렬화를 다 끝내야 하고, 끝내지 못하면 틱이 밀린다. 틱이 화면 체감에 주는 영향은 멀티플레이 노트의 틱 레이트 절에 있으니, 여기서는 서버 쪽 비용인 대역폭을 계산해 본다.

100명 배틀로얄에서 서버가 초당 30번 스냅샷을 보내고, 개체 하나가 델타 압축(지난번과 달라진 값만 보냄) 뒤 평균 24바이트라고 하자. 모든 플레이어를 모두에게 보내면 스냅샷 하나가 2396바이트라 UDP 패킷 하나에 안전하게 담기는 1200바이트를 넘어 둘로 나뉘고, 서버 한 대가 경기 하나에 58.8Mbps를 내보낸다. 각 플레이어 근처에서 보이는 30개체만 보내는 관심 영역(area of interest, AOI) 필터를 걸면 18.4Mbps로 준다. 멀리 있는 개체는 더 드물게 보내는 식으로 송신 횟수를 절반으로 줄이면 9.2Mbps다.

100명 경기의 서버 송신 대역폭: 모든 개체를 초당 30번 보내면 약 59Mbps, 관심 영역으로 30개체만 보내면 약 18Mbps, 송신을 초당 15번으로 줄이면 약 9Mbps다100명 경기 하나, 서버가 내보내는 Mbps0204060모두 보내기99개체 · 30Hz58.8Mbps한 사람 588kbps · 스냅샷 2396B · 패킷 2개관심 영역30개체 · 30Hz18.4Mbps한 사람 184kbps · 스냅샷 740B · 패킷 1개관심 영역 + 15Hz30개체 · 15Hz9.2Mbps한 사람 92kbps · 스냅샷 740B · 패킷 1개개체 24B(델타 압축 뒤) + 게임 머리 20B + UDP/IPv4 머리 28B로 계산
같은 100명 경기에서 무엇을 보내느냐에 따라 서버 송신량이 여섯 배 넘게 차이 난다. 관심 영역은 대역폭뿐 아니라 벽 너머 적의 위치를 보내지 않아 월핵도 막는다.
  • 대역폭은 서버 밀도를 정한다: 기기 한 대에 경기를 몇 개 올리느냐는 CPU만이 아니라 네트워크 카드와 클라우드의 송신 요금(egress)에도 걸린다. 송신이 줄면 같은 기기에 경기를 더 올리고, 요금도 준다.
  • 패킷 크기를 넘기지 않는다: 1200바이트를 넘는 UDP 데이터그램은 경로 어딘가에서 조각나거나 버려질 수 있다. 한 스냅샷이 패킷 여럿으로 나뉘면 하나만 잃어도 전체를 못 쓴다. 우선순위가 높은 개체부터 담고 넘치는 것은 다음 틱으로 미룬다.
  • 올라오는 쪽은 작다: 클라이언트가 보내는 것은 입력뿐이라 수십 바이트다. 다만 잃어버린 입력을 대비해 최근 입력 몇 개를 함께 실어 보내는 경우가 많다.

지역과 지연: 서버를 어디에 둘까

빛은 광섬유에서 1ms에 약 200km를 간다. 서울에서 미국 서부까지 왕복만 100ms가 넘으니, 서버를 어디에 두느냐가 틱 레이트보다 체감 지연을 더 크게 바꾼다. 그래서 게임은 지역(region)마다 플릿을 따로 두고, 경기를 잡을 때 플레이어가 어느 지역으로 갈지를 고른다. 기본 원칙과 핑의 정의는 네트워크 노트에 있다.

핑으로 지역 고르기: 서울의 플레이어가 서울·도쿄·싱가포르·미국 서부의 핑과 예상 대기를 잰다. 서울은 핑이 가장 낮지만 대기가 길고, 싱가포르와 미국 서부는 핑 한도를 넘어, 도쿄를 고른다서울의 플레이어지역마다 핑 측정서울 · 핑 8ms예상 대기 95초대기 60초 넘음 → 다음 후보도쿄 · 핑 34ms예상 대기 20초선택: 한도 안, 대기 짧음싱가포르 · 핑 72ms예상 대기 15초후보미국 서부 · 핑 135ms예상 대기 5초핑 한도 80ms 넘음
클라이언트가 지역마다 핑을 재고, 한도 안에서 가장 가까운 곳을 고르되 대기가 너무 길면 다음 후보로 넘어간다. 이 예에서는 서울이 가장 가깝지만 대기가 길어 도쿄를 고른다.
  • 핑으로 고른다: 클라이언트가 지역마다 둔 측정용 주소(UDP 에코 등)에 핑을 보내 왕복 시간을 매치메이커에 함께 보낸다. 매치메이커는 경기에 든 사람 모두에게 괜찮은 지역을 고른다. GameLift Servers의 대기열 문서도 플레이어 지연 값을 받아 지역의 우선순위를 정하고, 첫 지역에 자리가 없으면 다음 지역을 찾는 방식을 설명한다.
  • 지연과 대기를 바꾼다: 가장 가까운 지역만 고집하면 사람이 적은 시간에는 경기가 잡히지 않는다. 기다릴수록 핑 한도를 넓히는 식으로 둘을 맞바꾼다(게임 백엔드 노트의 매치메이킹 절).
  • 엣지와 전용망: 큰 클라우드 지역만으로는 모자란 곳에 작은 데이터센터(엣지)나 베어메탈을 더 둔다. 인터넷 경로 자체를 고치려는 회사도 있다. 라이엇 게임즈는 실시간 앱을 위한 인터넷 고치기 1편에서 일반 인터넷 경로가 실시간 게임에 맞지 않는 이유를 들고, 자체 백본(Riot Direct)을 깐 경험을 연재했다.
  • 지역마다 다른 서버, 하나의 계정: 경기 서버는 지역에 흩어지지만 계정·인벤토리 같은 백엔드는 한두 곳에 모이는 경우가 많다. 경기 서버가 백엔드를 부르는 일은 경기 시작과 끝에만 하도록 설계해, 대륙을 건너는 지연이 게임 도중에 끼지 않게 한다.

규모와 비용: 버퍼, 스팟, 그리고 업체

서버 기동에는 수십 초에서 몇 분이 걸린다. 매치메이커가 서버를 달라고 할 때 그제야 띄우면 플레이어가 그만큼 기다린다. 그래서 늘 Ready 서버를 몇 대 미리 띄워 두는 버퍼 방식으로 늘린다. Agones의 플릿 오토스케일러 문서의 Buffer 정책이 그대로 이 생각이다: Ready 서버를 몇 대 또는 몇 퍼센트 유지하고, 최소·최대 대수를 정한다.

하루 동안의 서버 수: 막대는 경기 중인 서버로 새벽에 16대, 저녁 8시에 132대까지 오른다. 계단선은 띄워 둔 서버로 늘 쓰는 서버보다 20% 또는 최소 10대 많다경기 중인 서버띄워 둔 서버 = 경기 중 + 버퍼(20%, 최소 10대)0601201801590시6시12시18시23시서버 수
하루 동안의 서버 수(가상의 예). 막대는 경기 중인 서버, 계단선은 띄워 둔 서버다. 버퍼는 저녁 피크에 앞서 미리 늘고, 새벽에도 최소 대수 아래로는 줄지 않는다.
  • 버퍼 크기: 버퍼가 작으면 몰릴 때 대기가 늘고, 크면 노는 서버 값을 낸다. 버퍼가 감당할 것은 "서버 한 대를 새로 띄우는 동안 들어오는 경기 수"다. 피크 시간이나 대회·업데이트 날처럼 예측되는 몰림은 시간표로 미리 늘린다.
  • 줄이기가 더 어렵다: 경기 중인 서버는 끌 수 없으니, 줄일 때는 Ready 서버만 지우고 경기 중인 기기가 비기를 기다린다. 경기를 기기 몇 대에 몰아 담아야(packing) 빈 기기가 빨리 생긴다.
  • 스팟·선점형 인스턴스: 클라우드가 남는 용량을 싸게 빌려주고 필요하면 2분 예고 뒤 회수한다. 경기가 끊길 위험이 있어, GameLift Servers의 스팟 플릿 문서처럼 온디맨드와 섞어 대기열에 넣고, 회수가 잦은 인스턴스 유형을 피해 배치한다. 경기 시간이 짧을수록 스팟이 잘 맞는다.
  • 클라우드와 베어메탈 섞기: 늘 쓰는 바닥 용량은 싼 베어메탈이나 예약 인스턴스로, 피크 위쪽만 클라우드로 받는 혼합(hybrid) 구성이 흔하다.

호스팅 업체도 바뀐다. Unity는 Multiplay 게임 서버 호스팅의 직접 지원을 2026년 3월 31일에 끝내고 소프트웨어를 Rocket Science Group에 넘겼으며, 서비스는 Rocket Science의 호스팅 페이지로 이어진다. 같은 해 Hathora는 AI 회사에 인수되며 게임 서버 사업에서 물러났고, GamesBeat 보도에 따르면 고객을 Nitrado로 넘겼다. 이 일로 멀티플레이를 잃게 된 게임도 있었다. 서버 쪽 코드를 업체 SDK에 얇게 감싸 두고(Ready·Shutdown·Health 정도), Agones 같은 표준 위에서도 돌 수 있게 해 두면 업체를 옮기는 비용이 준다.

장애와 복구: 체크포인트와 호스트 이전

서버는 죽는다. 세션형 경기는 죽으면 그 경기를 무효로 하고 보상을 돌려주는 정도로 끝내는 경우가 많지만, 지속 세계나 긴 협동 경기는 진행을 잃으면 안 된다. 그래서 서버가 상태를 주기적으로 밖에 저장하는 체크포인트를 둔다. 서버가 죽으면 관리 계층이 Unhealthy로 표시하고 새 서버를 띄워, 마지막 체크포인트를 읽어 이어 간다.

장애와 복구: 위는 서버가 체크포인트를 세 번 저장한 뒤 죽고, 새 서버가 마지막 체크포인트에서 이어 가며 그 사이의 진행만 잃는다. 아래는 P2P에서 옛 호스트가 나가자 피어 B가 새 호스트가 되고 피어 C가 B에 다시 붙는다전용 서버: 체크포인트에서 다시 시작시간 →저장 1저장 2저장 3잃는 구간서버 죽음새 서버가 이어감저장 3을 읽음P2P: 호스트 이전옛 호스트피어 B → 새 호스트피어 C연결 끊김복제된 상태로 경기를 이어 감
위: 서버가 상태를 세 번 저장한 뒤 죽고, 새 서버가 마지막 저장에서 이어 간다. 잃는 것은 마지막 저장 뒤의 진행뿐이다. 아래: P2P에서 호스트가 나가면 남은 피어 중 하나가 호스트를 이어받는다.
  • 무엇을 언제 저장하나: 거래·아이템 획득처럼 잃으면 안 되는 일은 그 자리에서 바로 백엔드에 쓰고(트랜잭션), 위치·체력처럼 조금 되돌아가도 괜찮은 것은 몇십 초마다 한꺼번에 저장한다. 바로 쓰는 쪽은 복제 지연에 따라 아이템이 둘로 늘거나(dupe) 사라지는 버그가 생기기 쉬운 곳이라 정확성이 중요한 시스템 노트의 멱등성·원장 기법을 그대로 쓴다.
  • 상태 저장소: 자주 바뀌는 세션 상태는 빠른 키-값 저장소(키-값 노트의 Redis 등)에, 영구 기록은 관계형 DB에 둔다.
  • 호스트 이전(host migration): 리슨 서버나 P2P에서 호스트가 나가면, 남은 피어들이 미리 정한 규칙(연결이 가장 좋은 사람 등)으로 새 호스트를 뽑고 나머지가 그에게 다시 붙는다. 피어들이 평소에 경기 상태를 복제해 두어야 이어받을 수 있다. 전용 서버가 있으면 이 문제 자체가 없다.
  • 다시 접속: 플레이어 쪽 장애(와이파이 끊김)가 더 흔하다. 서버가 경기 중 나간 사람의 자리를 잠시 비워 두고, 백엔드가 "지금 경기 중인 서버 주소"를 기억해 재접속을 받으면 된다.

프로토콜: UDP 위에 필요한 만큼만

TCP는 모든 바이트를 순서대로 전달한다. 게임에는 이것이 오히려 짐이다. 0.1초 전 위치를 담은 패킷 하나가 사라지면 TCP는 그것을 다시 받을 때까지 뒤에 온 최신 위치까지 붙잡아 둔다(head-of-line blocking). 최신 위치만 있으면 되는 게임은 그 패킷을 그냥 버리고 싶다. 그래서 실시간 게임은 대부분 UDP를 쓰고, 필요한 신뢰성만 그 위에 직접 얹는다.

게임 트래픽 계층 세 갈래: TCP는 모든 바이트를 순서대로 보내 패킷 하나가 늦으면 뒤가 기다린다. UDP 위에 게임이 순번과 ACK로 신뢰 계층을 얹으면 위치는 버리고 이벤트만 다시 보낼 수 있다. 브라우저에서는 QUIC 위 WebTransport의 스트림과 데이터그램을 쓴다TCP게임 메시지TCP: 순서 보장·재전송IP패킷 하나가 늦으면뒤의 것이 모두 기다린다UDP + 게임 신뢰 계층채널: 위치 / 이벤트순번·ACK 비트·재전송UDPIP위치는 새것만 쓰고 버린다이벤트만 다시 보낸다웹: WebTransport스트림 / 데이터그램QUIC (TLS 1.3 포함)UDPIP브라우저에서 쓰는UDP 계열 전송
TCP는 모든 메시지를 한 줄로 세운다. UDP 위 게임 신뢰 계층은 채널마다 다르게 다뤄 위치는 버리고 이벤트만 다시 보낸다. 브라우저에서는 QUIC 위의 WebTransport가 같은 일을 한다.
  • 게임 신뢰 계층: 패킷마다 순번을 달고, 받은 쪽은 최근 순번 32개쯤을 비트로 묶어 매 패킷에 함께 돌려보낸다(ACK 비트필드). 보낸 쪽은 어떤 패킷이 사라졌는지 알고, 그 안의 메시지 가운데 "반드시 가야 하는 것"(아이템 획득, 채팅)만 다시 보낸다. Glenn Fiedler의 UDP 위 신뢰성·순서·혼잡 회피 글이 이 구조를 단계별로 설명한다.
  • QUIC: UDP 위에서 연결, 암호화(TLS 1.3), 독립된 여러 스트림을 제공하는 표준이다(RFC 9000). 스트림끼리는 서로를 기다리지 않아 TCP의 줄 막힘이 스트림 안으로 좁혀진다.
  • 브라우저 게임: 브라우저는 UDP 소켓을 직접 열 수 없다. WebSocket은 TCP라 위의 문제가 그대로이고, MDN의 WebTransport API 문서가 설명하는 WebTransport는 HTTP/3(QUIC) 위에서 순서 없는 데이터그램과 스트림을 함께 준다. P2P라면 WebRTC 데이터 채널도 쓴다.
  • 보안: 서버 주소는 공개되므로 디도스와 위조 패킷을 전제로 설계한다. 접속 토큰(매치메이커가 발급하고 서버가 검사)으로 아무나 붙지 못하게 하고, 큰 응답을 작은 요청에 돌려주지 않는다(증폭 공격). 자세한 방어는 보안 노트에 있다.