서버/동기화

1. 동기화 기법

광란의슈가슈가룬 2025. 1. 24. 02:05

게임 서버를 만들 때 클라이언트끼리 싱크를 맞추는 것이 중요한데 이를 위한 기법들은 어떤 것이 있는지 알아보자.

1. LockStep

락스텝은 매 프레임마다 모든 플레이어의 입력값을 동기화해서 클라이언트에게 전송하는 방법이다.

 

간단하게 어떻게 수행되는지 단계를 보자.

1) 클라이언트가 자신의 명령(입력이나 행동)을 서버에 전송한다.

2) 서버는 클라이언트들의 명령을 수집한 후, 모든 클라이언트에게 동시에 뿌린다.

3) 클라이언트는 수신된 명령을 똑같이 처리한다.

 

장점

1) 모든 클라이언트가 똑같은 순서로 같은 입력들을 처리하기 때문에 일관된 상태를 유지할 수 있다.

2) 입력 명령만을 주고 받기 때문에 대역폭을 적게 사용하기 때문에 대역폭 관리가 수월하다.

 

단점

1) 서버가 모든 클라이언트의 입력이 들어올 때까지 대기하기 때문에 특정 클라이언트의 네트워크 상태가 좋지 못하다면 전체 게임이 지연될 수 있다.

2) 서버에서 명령만을 전달하기 때문에 연산은 클라이언트에서 수행하게 되고 클라이언트의 환경에 따라 부동소수점의 연산 방식이 다르기 때문에 이에 따른 오차가 발생할 수 있다. 따라서 부동소수점은 사용할 수 없다고 봐야된다.

3) 대기시간이 있으므로 빠른 반응이 필요한 게임에는 적합하지 않다.

 

모든 클라이언트가 동일한 명령을 동일한 시점에 수행하도록 강제하는 기법이기 때문에 정확한 동기화가 필요한 게임에 더 유리하다. FPS와 액션 게임과 같이 빠른 응답이 필요한 게임보단 턴제 전략 게임에 더 유리하다.

 

락스텝은 네트워크 지연에 굉장히 취약하기 때문에 현대의 게임에서는 보완 기법을 추가로 사용하거나 락스텝을 기반으로 하는 하이브리드 방식이 사용된다고 한다.

 

2. State Synchronization (상태 동기화)

상태 동기화는 서버가 게임의 상태를 관리하며 클라이언트는 서버에서 제공한 '상태'를 기준으로 화면을 렌더링하거나 사용자의 입력을 처리하는 방식이다.

 

작동 방식

1) 클라이언트가 입력을 서버에 전송한다.

2) 서버는 클라이언트들의 입력을 받아 상태를 업데이트한다.

3) 서버가 클라이언트들에게 현재의 상태를 전송한다.

 

장점

1) 모든 클라이언트가 동일한 상태를 전송 받으므로 일관성을 유지할 수 있다.

2) 상태 데이터를 주기적으로 전송하고 클라이언트가 이를 수신하여 갱신하기 때문에 상대적으로 간단하게 구현히 가능하다.

3) 서버가 상태 변경의 권한을 가지므로 치트와 같은 부정행위 방지에 효과적이다.

 

단점

1) 상태 데이터를 지속적으로 전송해야 하므로 전송량이 많아질 수 있다. 특히, 게임 내 객체 수가 많을 경우 문제가 심해진다.

2) 클라이언트가 상태를 받는데 시간이 걸리므로 지연이 생길 수 있다.

3) 복구가 어려워 클라이언트간의 상태 불일치 문제나 패킷로스가 생길 경우 복구하기 위한 추가적인 매커니즘이 필요하다.

 

상태 동기화에서는 클라이언트가 서버로부터 상태를 수신하지 못했을 경우 보간(interpolation)이나 외삽(extrapolation) 등을 통해 상태를 예측하기도 한다.

 

이를 통해 빠른 응답이나 정확한 동기화를 필요로 하는 FPS, MMORPG 등과 같은 장르에 주로 사용된다. 포트나이트, 배틀그라운드 같은 게임이 이에 포함된다. 물론 여러가지 보완을 거쳐서 사용하긴 한다.

 

최적화 방식

1) Update Rate 조정: 게임의 특성에 따라 업데이트 빈도수를 조절

2) 변경된 데이터만 전송: 후술할 델타 동기화

3) 레벨 오브 디테일(LoD): 플레이어가 직접 보지 않는 객체나 영역의 업데이트 빈도수를 줄임

4) 압축: 스냅샷 압축(Snapshot Compression)과 같은 기법으로 상태 데이터를 전송하기 전에 압축을 통해 대역폭의 부담을 줄임

 

3. Delta Synchronization (델타 동기화)

델타 동기화는 상태 동기화의 효율성을 높이기 위해 전체가 아닌 변경된 부분(델타)만 전송하는 방식이다. 이를 통해 대역폭을 절약할 수 있다.

 

작동 방식

1) 게임이 시작되면 초기 상태를 클라이언트들에게 전송한다.

2) 서버는 상태를 주기적으로 모니터링하고 특정 상태가 변경되었을 때 변경된 데이터만 클라이언트에게 전송한다.

3) 클라이언트는 변경된 데이터를 수신해 전체 상태를 업데이트 한다.

4) 서버는 주기적으로 전체 상태를 클라이언트와 비교하거나 특정 이벤트 발생 시 전체 상태를 업데이트하여 불일치를 방지한다.

 

장점

1) 델타 동기화는 예를 들어 100개의 유닛 중 5개만 움직였다면 그 5개의 변경 데이터만 전달하기 때문에 대역폭 사용량을 크게 줄일 수 있다.

2) 필요에 따라 전체 상태를 동기화하는 방식을 결합하여 싱크가 맞지 않는 문제를 해결할 수 있다.

 

단점

1) 변경된 상태만 감지하고 전송하는 매커니즘이 필요하므로 구현이 복잡하다.

2) 패킷이 손실되거나 수신된 데이터를 잘못 적용할 경우 클라이언트 간 불일치가 발생할 수 있어 이를 예방하기 위한 추가적인 보완이 필요하다.

 

구현 요소

1) 변화 추적(Dirty Flags): 객체의 상태 변화를 추적하기 위해 사용된다. 객체가 상태를 변경할 때 Dirty Flag를 true, 서버가 이 객체를 전송한 후 Dirty Flag를 false로 설정하여 변화를 감지한다.

2) 클라이언트의 상태 불일치가 감지되면 서버가 전체 상태를 보내 동기화한다. 또한, 주기적으로 전체 상태를 전송해 불일치를 예방할 수 있다.

 

 

변경된 데이터만 전송하기 때문에 효율성과 유연성이 필요한 게임에 적합하다. MMORPG, RTS, MOBA와 같이 수많은 객체와 플레이어가 존재하고 이런 오브젝트들의 변화가 빈번한 게임 장르에 사용된다.

 

상태 동기화 vs 델타 동기화

 

4. Event-Based Synchronization (이벤트 기반 동기화)

이벤트 기반 동기화는 특정 상태나 델타 데이터를 전송하는 것이 아닌 특정 행동, 명령인 이벤트를 전달하는 방식이다.

 

작동 방식

1) 클라이언트에서 "A가 이동", "A가 총 발사"와 같은 특정 행동(이벤트)이 발생하면 서버로 이를 전송한다.

2) 서버는 이벤트를 받아 이를 계산하고 다른 클라이언트에게 이벤트를 전달한다.

3) 클라이언트는 받은 이벤트를 자신의 게임 상태에 반영한다.

 

장점

1) 상태가 아닌 명령(이벤트)만을 전달하기 때문에 데이터의 크기가 작다.

2) 이벤트는 명확하고 간단한 구조로 전달되기 때문에 구현이 쉽고 직관적이다.

3) 클라이언트는 이벤트를 받는 즉시 업데이트를 할 수 있으므로 실시간성 측면에서 유리하다.

4) 이벤트는 다양한 게임 매커니즘을 추가, 변경하기 비교적 간단하므로 확장성이 좋다.

 

단점

1) 역시 이벤트가 전송되지 않으면 상태 불일치가 발생할 수 있다. 따라서 재전송 매커니즘이 필요하다.

2) 서버가 모든 이벤트를 처리하고 전송해야 하므로 이벤트가 많아지면 서버에 부하가 걸릴 수 있다.

3) 지연 발생시 불일치가 생길 수 있으므로 이를 보정하는 매커니즘이 필요하다.

 

MMO와 같이 이벤트가 많은 장르는 서버에 부하가 걸릴 수 있고, 턴제 전략 게임은 락스탭이 훨씬 적합하므로 이런 장르에는 어울리지 않는 기법이다.

 

최적화 방안

1) 유사한 종류의 이벤트를 묶어서 전송하여 네트워크 부하를 줄임

2) 주기적 상태 동기화와 결합하여 상태 불일치를 방지

3) 클라이언트가 이벤트를 기다리지 않고 예측, 보간을 사용해 처리하고 서버에서 보낸 데이터가 있다면 보정함

 

동기화 기법들 비교

특징 상태 동기화 델타 동기화 이벤트 기반 동기화
전송 데이터 전체 상태 전송 변경 데이터(델타) 전송 이벤트 전송
네트워크 효율성 상태의 크기에 따라 다름 상태 동기화보다 효율적 높음
서버 역할 상태 계산 및 주기적 동기화 상태 변경 감지 및 전송 이벤트 검증 및 처리
주요 장르 FPS, RPG MMO, 대규모 객체 동기화가 필요한 게임 MOBA, 액션 게임, 실시간 대전

 

 

5. Dead Reckoning

데드 레코닝은 클라이언트 또는 서버가 현재의 상태를 기반(위치, 속도, 방향 등)으로 미래의 상태를 예측하여 출력하는 기법이다. 주로 네트워크 지연을 보완하고 클라이언트 간 불일치를 줄이기 위해 사용된다. 이 기법은 위에 서술한 다른 기법같이 직접적으로 동기화하는 기법은 아니고 다른 방식들을 보완하는 보조 기법으로 보면 될 것 같다.

 

작동 방식

1) 서버는 초기 상태를 클라이언트에게 전송한다.(위치, 속도, 방향 등 예측 가능한 데이터 포함)

2) 클라이언트는 받은 상태를 기반으로 다음의 상태를 예측한다.

3) 서버는 주기적으로 상태를 전송하며 클라이언트는 예측 상태와 실제 상태의 차이를 보정한다.

 

목표

1) 서버에서 클라이언트로 데이터가 도달하기 전에 클라이언트가 객체의 상태를 예측하여 지연을 최소화

2) 객체의 움직임이 끊기지 않고 자연스럽게 이어지도록 만듦

3) 서버가 상태를 자주 전송하지 않고, 클라이언트가 예측으로 상태를 처리하므로 데이터 전송량 감소

 

장점

1) 상태를 자체적으로 예측하므로, 지연으로 인한 끊김이 줄어든다.

2) 네트워크 품질이 좋지 않아도 화면상에서 객체가 자연스럽게 이동하는 것처럼 보이게 한다.

3) 서버는 상태를 자주 전송하지 않아도 되므로 트래픽이 줄어든다.

 

단점

1) 객체의 실제 움직임이 예측된 움직임과 다를 경우 상태 불일치가 발생한다.

2) 예측이 틀렸을 경우 보정 과정에서 일명 튀는 현상이 발생할 수 있다.

3) 객체의 움직임 예측, 상태 비교, 보정 로직을 구현하는 데 비용이 많이 들어간다.

 

사용 사례

1) 레이싱 게임에서 차량의 움직임이 네트워크 지연에도 끊기지 않도록 함

2) FPS, MOBA, MMO등에서 캐릭터들의 움직임을 예측해 트래픽을 줄이고 지연이 없는 것 처럼 보여줌

 

최적화 방안

1) 서버와 클라이언트의 상태 차이가 특정 임계값을 초과할 때만 보정하여 튀는 현상을 줄임

2)  상태 갱신 주기를 조정하여 네트워크 부하를 줄이면서도 지연을 최소화

3) 다양한 운동 모델을 사용하여 예측의 정확도를 높임