🎯 글을 쓰게 된 이유
리그 오브 레전드에서 챔피언을 움직이거나, 온라인 게임에서 몬스터를 잡거나, 총 게임을 할 때....
우리는 매 순간 수많은 데이터를 서버와 주고받고 있다.
문득 궁금해졌다.
내가 게임에서 한 걸음 움직일 때마다 서버에 API 호출을 하는 걸까?
아이템을 획득할 때마다 DB에 저장되는 건가?
실시간으로 다른 유저와 싸우는데 어떻게 렉이 안 생기지?
그래서 이번에는 게임이 서버와 통신하는 방식에 대해 파헤쳐보기로 했다.
🎮 게임 통신의 기본 분류
게임 서버 통신을 이해하려면 먼저 게임을 크게 세 가지로 분류해야 한다
1. 실시간 게임 (FPS, MOBA, 배틀로얄)
- 밀리초 단위의 빠른 반응이 필요
- 다수 유저가 동시에 상호작용
- 지연시간이 게임 플레이에 직접적 영향
2. 턴제/비실시간 게임 (카드게임, 퍼즐게임)
- 상대적으로 느린 통신도 괜찮음
- 정확성이 속도보다 중요
- HTTP API 통신이 일반적
3. 하이브리드 게임 (MMO RPG)
- 실시간 전투 + 비실시간 컨텐츠 혼재
- 상황에 따라 다른 통신 방식 사용
🔌 실시간 게임의 통신: UDP vs TCP
UDP가 선택받는 이유
실시간 게임에서는 주로 UDP 프로토콜을 사용한다.
TCP는 데이터를 안정적이고 순서대로 전달하지만, 이를 위해 IP 위에서 패킷 재전송을 기다리는 동안 최신 패킷들을 큐에서 대기시킨다. 이를 "head of line blocking"이라고 하며 게임에서는 큰 문제가 된다.
📝 UDP vs TCP 차이점
- UDP: 연결 확인 없이 일방적으로 데이터 전송, 빠르지만 일부 손실 가능
- TCP: 연결을 확인하고 순서를 보장하지만, 손실된 패킷을 기다리느라 지연 발생
📝 Head of Line Blocking이란?
게임 서버가 초당 10번 월드 상태를 클라이언트에게 보낸다고 가정하자.
각 클라이언트는 시간을 진행시키며 서버로부터 받은 가장 최신 상태를 보여주려 한다.
하지만 시간 t=10.0의 패킷이 손실되면, TCP에서는 이미 도착한 t=10.1, t=10.2 패킷에 접근하기 전에 먼저 재전송을 기다려야 한다.
UDP에서는 패킷이 드롭되면 그걸로 끝이다.
다음 패킷이 평소와 똑같이 계속 처리된다. TCP에서는 패킷이 드롭되면 드롭된 패킷이 성공적으로 재전송될 때까지 데이터 전송이 멈춘다.
이는 수신자가 드롭된 패킷을 제때 받지 못할 뿐만 아니라, 후속 패킷들도 지연된다는 의미다.
🎯 움직임 한 걸음마다 서버 통신할까?
결론부터 말하면: 아니다!
게임에서 우리가 한 걸음 움직일 때마다 개별 API를 호출하지는 않는다.
대신 다음과 같은 최적화된 방식을 사용한다
1. 배치 처리 (Batching) 여러 개의 작은 액션을 모아서 한 번에 전송한다.
2. 델타 압축 (Delta Compression) 변경된 부분만 전송해서 데이터량을 줄인다.
3. 상태 보간 (State Interpolation) 클라이언트에서 서버 데이터를 받아 부드럽게 보간한다.
📝 델타 압축이란?
전체 상태를 매번 보내는 대신 이전 상태와 달라진 부분만 보내는 기술이다.
Colyseus 같은 멀티플레이어 프레임워크에서는 서버에서 클라이언트로의 자동 상태 동기화가 델타 압축되어 제공된다.
📝 상태 보간(State Interpolation)이란?
서버에서 받은 불연속적인 데이터 포인트들 사이의 중간값을 계산해서 부드러운 움직임을 만드는 기술이다.
예를 들어, 서버에서 0.1초마다 다른 플레이어의 위치를 받지만, 우리 화면은 60fps(초당 60프레임)로 그려진다.
🗄️ 데이터베이스 저장 시점과 전략
언제 DB에 저장할까?
게임에서 저장하는 요령은 플레이어의 경험을 재현하는 데 진정으로 필요한 것만 저장하는 것이다.
많은 게임들이 레벨 끝과 같은 특정 장소에서만 저장을 허용하는데, 이 경우 새로운 레벨 번호와 이전 레벨들의 결과(남은 체력, 획득한 아이템 등)만 저장하면 된다.
1. 즉시 저장해야 하는 데이터
- 계정 정보 변경: 레벨업, 경험치 획득
- 아이템 획득/사용: 희귀 아이템, 유료 아이템
- 재화 변동: 게임 내 화폐
- 게임 결과: 승패, 점수
2. 주기적 저장하는 데이터
플레이어 위치 추적 방식에 따라 달라진다.
매번 움직일 때마다 DB에 쓰는지, 아니면 서버 메모리에 위치를 보관하고 2~10분마다 "플레이어 통계 저장"으로 DB에 쓰는지에 따라 구조가 달라진다.
3. 차등 저장 (Differential Saves)
주요 기법 중 하나는 차등 저장이다.
기본값이 아닌 상태만 저장하는 것이다.
"게임 월드의 모든 오브젝트의 상태와 위치 저장"과 "플레이어가 움직이거나 변경한 게임 월드 오브젝트들의 상태와 위치만 저장"을 비교해보라.
💾 게임에서 사용하는 데이터베이스 종류
1. 관계형 데이터베이스 (RDBMS)
MySQL/PostgreSQL
- 용도: 계정 정보, 아이템 정보, 길드 시스템
- 특징: ACID 보장, 복잡한 쿼리 가능
- 사용 사례: 유저 계정, 결제 내역, 친구 목록
2. NoSQL 데이터베이스
인메모리 데이터베이스
자주 사용되는 데이터를 메모리에 저장하여 더 빠른 검색을 가능하게 하고, SSD(Solid State Drive) 사용으로 더 빠른 읽기/쓰기 속도를 통해 지연시간을 줄인다.
3. 클라우드 데이터베이스
Google Spanner
Spanner는 단일 전 세계 트랜잭션 권한으로 작동할 수 있어서 게임 인벤토리 시스템에 탁월한 적합성을 보인다.
거래, 판매, 선물, 또는 한 플레이어에서 다른 플레이어로 전송될 수 있는 게임 내 통화나 아이템은 대규모 게임 백엔드에서 도전 과제를 제시한다.
🔄 실제 게임에서 일어나는 일
실시간 게임에서의 스킬 처리 과정
MOBA나 FPS 게임에서 스킬 발사를 예시로 보자:
- 플레이어 입력: 플레이어가 Q 스킬 키를 누름 → 클라이언트가 스킬 사용 이벤트를 서버에 전송
- 서버 계산: 서버는 스킬이 발사되는 투사체 궤적을 계산 (발사 위치, 방향, 속도)
- 충돌 검사: 서버가 해당 궤적과 주변 챔피언들의 좌표를 실시간으로 비교 → 충돌 여부 판정
- 피해 적용: 맞았다면 피격 대상의 체력 감소 처리 및 상태 효과 적용
- 결과 동기화: 그 결과를 해당 게임에 접속한 모든 클라이언트에 브로드캐스트
📊 성능 최적화 전략
캐싱의 중요성
지역간 매칭에서의 지연시간 차이, 예를 들어 PUBG에서는 피크 시간이나 라이브 이벤트 중 서버에 높은 수요가 있을 때 서버 성능 저하로 인해 고르지 않은 게임플레이로 이어질 수 있다.
이는 경쟁 게임에서 중요한 실시간 응답성에 영향을 미친다.
적절한 캐싱이 이러한 문제를 완화한다.
확장성 문제
게임의 인기가 기존 데이터베이스가 단일 노드 데이터베이스에서 모든 것을 처리할 수 있는 능력을 초과할 수 있다.
게임 유형에 따라 데이터베이스는 플레이어 부하를 처리하는 데 필요한 작업 수와 저장된 데이터 양 때문에 어려움을 겪을 수 있다. 이는 종종 게임 개발자들로 하여금 추가 성능을 위해 데이터베이스를 샤딩하거나 계속 증가하는 테이블을 저장하게 한다.
🎯 결론
게임 서버 통신의 세계를 파헤쳐본 결과, 우리의 한번 클릭당 api 호출은 없다.
내가 생각하는 서버의 통신인 RESTapi 통신 방식이 아닌 주로 UDP를 이용한 소켓 통신을 사용하는 방식이었다.
가장 인상적인 점은 "게임 경험을 위한 기술적 트레이드오프"였다.
TCP의 신뢰성과 순서 보장 vs UDP의 속도, 보안 vs 성능, 안정성 vs 반응성
게임 개발자들은 매 순간 이런 선택의 기로에서 최적의 밸런스를 찾아내고 있다.
좀 더 상세하게, 어떤 프로세스들을 거치는지, 게임 개발 프레임워크나 통신 네트워크에 대해서 자세히 알아보고 싶은 마음도 생겨,
다음번에는 좀 더 딥하게 플로우 다이어그램을 그려가며 공부해보고 싶다.
'백엔드 멘토링' 카테고리의 다른 글
번역기가 우리들의 말을 번역해주는 방법 (3) | 2025.08.25 |
---|---|
구글은 어떻게 그렇게 빠른 검색을 지원할까? (0) | 2025.08.23 |
인스타그램이 우리들의 관심사를 알아내는 방법 (0) | 2025.08.22 |
카카오 T 에서 최단거리를 탐색하는 방법 (1) | 2025.08.21 |
[Spring] 조회 성능 테스트 및 조회 성능 개선 일지 (1) | 2025.04.18 |