Nexon OC Studio
Technical Director
구승모
최종 일관성, 서버 되감기 기법, 그리고 결정성에 관해
CAP 정리를 통한 게임 동기화 이야기
• 캘리포니아 오랜지
카운티에 위치
• 주로 Amazon, Blizzard,
NC, Riot, Sony 출신의
개발진으로 구성 (이 게임
회사들 물리적으로 10분 이내에 위치…)
• PC/Console
• 주로 북미/유럽 대상
발표자 소개
• Nexon OC 테크니컬 디렉터
• WOW 때문에 인생 크게 바뀐 케이스
• 이 게임 때문에 게임 업계로 이직
• NCSOFT 서버 프로그래머
• Bluehole 선임 엔지니어 / 서버 아키텍트
• NHN NEXT 게임 전공 교수
• Amazon Games 수석 엔지니어
• NDC 2014
• “사설 서버를 막는 방법들“ (우수세션)
전투/작전 사령관 캐릭 하나씩, 오리지널 낙스라마스 공대
2005년에만 순수 게임 플레이 시간: 160+일
목차
1. CAP 정리 그리고 최종 일관성
2. 멀티플레이어 게임 동기화 101
3. 서버 되감기를 통한 동기화
4. 게임 로직과 결정성
이 세션에서 다루지 않는 것들
• 여러가지 Dead Reckoning 테크닉*
• 분산 시스템에서의 합의 알고리즘 또는 상태 복제 프로토콜들*
• PACELC 같은 CAP의 확장 정리*
• 각종 일관성 모델*
* 자세한 내용은 참고 자료 슬라이드에…
CAP 정리 그리고 최종 일관성
CAP Theorem
• 2000년, Eric Brewer*
• 튼튼한(robust) 분산 시스템 설계시
기술적인 선택에 도움을 주는 정리
• 일관성 (Consistency)
• 가용성 (Availability)
• 분할용인 (Partition Tolerance)
• C+A+P를 동시에 모두 만족하는
시스템은 없음
• 2개 선택하세요
• NoSQL과는 사실상 관련 없음
IMG From: https://docs.deistercloud.com/Technology.50/NoSQL/index.xml
NoSQL
• 대량의 데이터를 빠르게 처리하기 위함
• 데이터간 관계가 단순
• Schemaless
• Key-Value, Key-Document 형태가 일반적
• 단순하지만 고성능 및 고가용성을 제공
• 내부적으로 스토리지 구조가 샤딩 및
복제본을 두는 형태
• 실전에서 많이 사용되는 것들*
• MongoDB, Cassandra, DynamoDB, …
Node1
Node2
Node3
Client1 Client2
비동기 업데이트
Writes
Read
AWS DynamoDB 예
• DynamoDB의 데이터 읽기/쓰기
• Write는 3군데의 스토리지에 분산 복제 저장 (2군데 쓰면 바로 응답리턴)
• Read는 2가지 방법 중 선택
• Default Read: 3개의 노드중 가장 먼저 응답하는 하나에서 읽기. 이 경우
과거의 데이터를 읽어올 가능성이 있음 (가용성을 선택)
• Consistent Read: 모든 노드의 데이터가 동기화된 후에 읽어옴 (일관성 선택)
Client1
 DynamoDB Storage (3벌 복제 및 분산 저장)
Client2 Client3
Read ReadWrite
 Client2와 Client3은 서로 다른 상태를 볼 수 있음
최종 일관성 (Eventual Consistency)
• A+P 시스템 기반위에 뒤늦게 일관성을 맞추는 방식*
• 순간적으로 과거의 데이터를 볼 수 있지만, 결국 일관성이 맞춰짐
• (참고) AP 시스템이라고 해서 최종 일관성을 무조건 만족하는 것은 아님
(e.g.) AWS SQS
IMG From: http://www.cloudcomputingpatterns.org/eventual_consistency/
멀티스레드 환경에서의 일관성
• 싱글스레드
• C + A: 일관성(C) + I/O 등으로 인한 블로킹이 없다면 (A)
• Lock으로 동기화하는 멀티스레드 환경
• C + P: 잠금을 통한 일관성 유지 (C) + 멀티스레드 (P)
• 여러 스레드가 항상 동일한 공유자원 상태를 볼 수 있음 (Consistency)
• 이 방법은 Availability가 보장되는가?
• 하나의 스레드가 잠금 중일때는 다른 모든 스레드는 대기해야 함
(순간적으로 Available하지 않음을 의미)
• Lock안에서 I/O등을 통한 대기가 걸린다면? Lock Convoying…
최종 일관성을 통한 멀티스레드 성능 향상
• 일관성을 약간(?) 양보할 수 있는 경우
• 특정 스레드가 과거의 상태를 잠깐 보는 한이 있어도 스레드가 공유자원
접근시 대기하지 않도록 함
• C + P 대신 C + A를 선택
• 대신, 결국에는 모든 스레드가 같은 상태로 맞춰질 수 있도록 구현
• How-to
• Thread Local Storage별 자료구조를 두고 업데이트 큐(lock-free or wait-
free queue)를 활용하여 스레드별 업데이트
• 읽기는 스레드 로컬 접근, 업데이트는 큐를 활용하여 비동기적으로
• (예) https://github.com/zeliard/Dispatcher/blob/LB_version/JobDispatcher/LoadBalancer.h
TERA Case Study
• 처음에는, 하나의 맵을 두고 여러 로직 스레드가 경합
• ReadLock을 통한 검색, WriteLock을 통한 업데이트
• 모든 스레드가 동일한 맵 상태를 볼 수 있지만 (일관성 유지)  CPU 100% !!
Actor
11 12 13
21 22 23
31 32 33
Map
C C’ Worker Thread #1
Waiting…
Worker Thread #2
Lock – Update - Unlock
Worker Thread #n
Waiting…
Update
Queue
U
(1) Push Map
Update Task
0
N
1
2
3
…
Queue Index
Replicated Map
Info
Thread Local Map 1
Thread Local Map 2
Thread Local Map N
Sequence of
Task Execution
(2) Pop & Execute
Update Task
U
D
D
Current TLS index: 2Current TLS index: 1
Current TLS index: 1
Current TLS index: 1
Current TLS index: 2
Current TLS index: 2
D
TLS를 이용한 최종 일관성으로 변경
순간적으로 특정 스레드는 과거의 상태를 볼 수 있지만 Lock 경합이 없음
 스레드 입장에서는 맵 자료구조가 언제나 가용(available)한 상태  성능 향상
멀티플레이어 게임 동기화 101
싱글 플레이어 게임의 처리 과정
Inputs
Simulate
Render
Wait
States
events
timer
State State State
Time
Frame Per Second (FPS)  이 루프가 1초에 몇 번 도는가?
C + A 시스템
멀티 플레이어 게임 동기화 타입
동기형 (타입1)비동기형 동기형 (타입2)
비동기형 (Asynchronous) 게임
• 주로 웹서비스 형태의 백엔드
• 2-tier: web servers + data store
• 3-tier: web front + app servers + data store
• HTTPS를 이용한 보안성 확보가 쉬움
• 연결 유지가 필요 없어 접속이 불안정한 환경에서 유리
• 모바일 게임 및 소셜 게임 장르에 적합
• (요즘 대세) 서버리스 형태로도 백엔드 구축 가능
• API Gateway, Cloud function, Lambda, …
Client
LB Web Server
Browser
Web Server
Client
Browser
Web ServerHTTP
비동기형 게임의 일반적인 동기화 방식
Request/Response 구조
• 웹의 특징을 그대로 물려 받음
• Atomic, Stateless
• 플레이어간 순서 보장이 필요할 경우
• 사과를 친구가 먼저 수확한 경우 어떻게 처리?
• 주로 캐시서버나 DB에서 동기화
• 수동적: Server-initiated Action 어려움
• 몬스터의 선공과 같은 능동적 NPC 행동 불가
Client
Web Server
State State State
Response
Request
동기형(Synchronous) 게임
• 실시간 동기화
• 멀티플레이어 게임도 하나의 분산 시스템이라고 볼 수 있음
• 사실 CAP는 분산 시스템 어디서나 적용할 수 있는 이야기
• 원격지의 상태 복제를 통해 동기화
• 게임 스타일에 따라 일관성과 가용성 중 선택해야 함
• 네트워크 게임 == 분산 환경 (즉, P는 필수 요소)
• 선택지: 가용성(A) vs 일관성(C)
• 서버가 게임 로직 처리(Simulate) 및 동기화
• 클라이언트는 서버를 통한 간접 연결
• NPC를 서버가 능동적으로 활용(drive)할 수 있음
• 주로 사용되는 장르: FPS, MMORPG, MOBA, Sports
동기형 (타입1: 서버 동기화)
Simulate
States
Inputs
Render
Wait
eventsServer
state info
• Client-Server 아키텍처
• 클라이언트에서 발생하는 이벤트는 서버에서 모두 모아 계산한 후 클라이언트로 방송
• 자본주의(?) 동기화 / 낙관적(?) / A+P System
• 서버가 먼저 진행  클라는 따라올테면 따라와봐  네트워크 속도가 빠른 클라일수록
서버와의 격차가 가장 적음 (유리)
• 서버/클라간 시간차는 클라가 알아서 Dead Reckoning*
Server
Client A
Client B
NPC
NPC
NPC
A
B
A
A
B
B
Event A
Event BNPC Event
서버 동기화 (Server-Authoritative)
클라가 늦게 받을수록
튀는 현상 발생
IMG From: http://m.post.naver.com/viewer/postView.nhn?volumeNo=11513471&memberNo=16036253
Rubber Banding?
서버 동기화 TickRate 고려사항
• 서버 시뮬레이션 TickRate 및 방송 주기는 얼마로 할 것인가?
• 높은 TickRate는 더 정확한 판정 (이후 설명할 서버 되감기에도 더 유리)
• 그러나 더 많은 CPU와 네트워크 대역을 요구 (인프라 비용 상승)
• (예) 고오급시계의 기본 서버 방송 주기는 20Hz, 커스텀 모드는 60Hz 까지
방송 범위와 보안
• 시야 범위 (Area Of Interest)
• AOI 관리를 통해서 클라가 알아야 하는 범위의 정보만 전송
• (참고) UE4 Dedicated Server의 Network Relevance
• AOI 범위가 좁을수록 플레이어 경험이 불쾌해짐 (시야가 좁아짐)
• AOI 범위가 넓을수록 패킷 처리량이 많아지고 보안에 불리해짐
• (예) PUBG
• 원거리 저격 때문에 멀리 있는 적 정보까지 동기화 대상
• 벽뒤에서 갑툭튀(?) 때문에 AOI Occlusion Culling을 적용하기도 어려움
• 상대 플레이어로부터 주기적으로 이벤트를 모아 각자 시뮬레이션
• RTS 및 과거의 AOS 장르에서 주로 사용
동기형 (타입2: Lock-Step 동기화)
Inputs
Simulate
Render
Wait
States
peer
events
Inputs
Simulate
Render
Wait
States
Compare Compare
Same hashval?
Dropped from the game?
IMG From: http://starcraft.burningblade.org/stories/index.html
Lock-Step 형태의 동기화 방식
• 각각의 클라이언트는 모두 아래와 같은 형태의 Queue를 유지
• 공산주의(?) 동기화 / 비관적(?) / C+P System
• 다 함께 같이 간다  클라가 하나라도 멈추면 다 같이 기다린다
• 서버 동기화 방식과 다르게 특정 클라만 튀는 현상 없음
• 월드의 전체 내용을 서로 공유하기 때문에 해킹에 취약 (맵핵/헬퍼)
• 라운드간 Lag 숨기기 기법을 최대한 활용*: (예) 스타크 마린의 Pre-Anim & Sound play
events eventsevents나
상대1
상대2
Round
0 ms 50 100 150
Round Round Round
events
events events
모든 Peer들의
입력이 모이면
해당 Round를
처리(Simulate)
하고 렌더링
특정 Peer의 정
보가 제시간에
도달하지 않으
면 Block
??
events
Waiting for players?
Lock-Step 동기화 TickRate 고려사항
• Lock-Step 동기화 주기(Round 길이)에 영향
• 스타크래프트 Low/High latency 옵션 예
• Low: Waiting for players 화면을 볼 가능성이
더 높지만 반응성이 더 좋음
• TickRate 높고, Round 길이 짧음
• High: 게임은 더 부드럽게 진행되지만
반응성이 더 느림
• TickRate 낮고, Round 길이 김
• (예) CR게임 동기화
• 글로벌 원 서버 (A社 미국 클라우드)
• 1초 Round 동기화: 지구 반바퀴 지연 0.5s 이내
Re:CAP
• 서버 동기화
• A+P System: 플레이어들에게 랙없는 경험을 최대한 주기 위해 항상
응답 가능한 상태(Available)를 유지
• Lock-Step 동기화
• C+P System: 플레이어들에게 공평한 경험을 주기 위해 항상
일관성(Consistent)이 있는 상태를 유지
서버 되감기를 통한 동기화
왜 Lag을 보정해야 하는가?
• 인터넷은 빨라졌지만…
• 멀티플레이어 게임에 국경이 없어지고 있음
• 글로벌 원빌드, 더 먼거리의 플레이어간 대전
• 역설적으로 플레이어들은 랙에 노출이 더 심해짐
• 결국 랙을 핸들링 해야 함
• 가까운 거리상의 플레이어들끼리 매칭하도록 강제하거나,
• 랙을 무시하고 클라이언트가 최대한 알아서 보정 하거나,
• 게임 시스템이 알아서 보정해주는 트릭을 사용해서 플레이어를
속이거나(?)
동기화 트렌드
• 어차피 Lag을 피할 수 없다면…
• 일관성을 맞추기 위해 누군가를 기다려야 한다는 것은 불쾌한 경험을 줌
• CP 시스템은 아주 제한적으로 사용 가능 (예: Round주기가 500ms 이상)
• 최악의 경우에도 Round 주기 이내에 응답이 오는 경우를 가정
• 누군가를 기다리지 않는 서버 동기화의 방식을 채택 (AP 시스템)
• 여기에 최종 일관성을 통한 최대한의 공정함을 보장하는 방법 사용
• 공정한 플레이 및 쾌적한 느낌을 주기 위해 Lag을 보정
• 서버 되감기를 통한 동기화*
서버 되감기를 통한 동기화
• 서버는 클라이언트가 보던 과거의 시점으로 돌려서 판정
• 퀘이크, 듀크뉴캠, 콜오브듀티 등이 이 방법 사용
• 게임 시뮬레이션은 서버와 클라이언트에서 모두 각자 함
• 클라이언트의 입력 및 자체 시뮬레이션 결과를 서버에 전송
• 서버에서 클라이언트의 입력 시점으로 되돌려서 시뮬레이션
• 클라에서 보내준 자체 시뮬레이션 결과와 같다면 OK
• 클라에서 보내준 자체 시뮬레이션 결과와 다르다면 클라이언트에게 알려줌
• 서버에서의 최종 결과가 도착하면 클라이언트에서 보정
• 클라에서 예측을 통한 시뮬레이션을 먼저 하고 진행하는 것이 일반적
• 예: LOL의 틱당 골드 증가
서버 되감기 시각화
IMG From: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
아주 쉬운 예
• 울트라 캡숑 쉬운 예제: Pong Laser 게임
P2
P1
Shoot a Laser
Game World
기본 원리
TIME
CLIENT SERVER
Latency
Shoot
Target Hit
Target
Move
Target
Move
Shoot
Target Hit
Target
Hit?
Target Hit
Approved
Server
Rewind
상태 변화 요약
• 서버가 클라에게 보낸 월드 상태 • 클라가 서버에게 보낸 입력 변화
WorldFrame TARGET PosY
1 2.0
2 3.0
3 5.0
4 8.0
WorldFrame Client Input FR Shoot
1 1 No
2 2 No
2 3 No
3 4 Yes
클라이언트가 알고 있는 WorldFrame 기준으로 서버가 상태를 되돌려 판정
Real Code Sample
• Pong Laser
• https://github.com/zeliard/PongRewind
• 일부러 서버/클라이언트 양측에 랜덤 Delay를 넣어서 Desync상황 연출
최대한 쉽고 깔끔하게 만드려고 노력했으나 급하게 만든 날코딩 양해 구함
Pseudo Code Level
• 클라이언트가 보내는 정보
Client Input (Request)
• 서버가 방송하는 정보
Game Status (Broadcast)
서버 되감기를 위한 히스토리 유지하기
• 서버측에서 WorldFrame별 상태 보관
• 과거의 상태가 필요한 오브젝트에 대해 WorldFrame(서버프레임)별 스냅샷
• 참고: 이번 예제는 너무 간단하므로 월드 상태를 통째로 유지함
• 실전에서는 되감기가 필요한 객체에 대해서만 제한적으로 유지하는 것을 추천
• Client Update Loop
1. 현재 플레이어의 입력을 얻는다
2. 플레이어 입력을 기반으로 시뮬레이션(상태 업데이트)을 한다
3. 업데이트된 상태에 대한 해시를 구한다
4. 서버에 플레이어의 입력 및 해시 값을 보낸다
5. 클라이언트 입력에 대한 History를 기록한다
• Desync시 클라이언트 Replay를 위해 Client Input Frame 단위로 보관
Client Logic
https://github.com/zeliard/PongRewind/blob/master/PongClient/PongClient/GUIController.cpp#L145-L164
Client Logic
• Client Receive Handler
1. 서버로부터 도착한 최신 상태를 덮어쓴다
• 최신의 서버 상태로 강제 업데이트를 의미하나 바로 렌더링에 반영할지,
클라이언트에서 더 부드럽게 보정(데드레커닝)을 할지는 선택의 문제
https://github.com/zeliard/PongRewind/blob/master/PongClient/PongClient/GUIController.cpp#L233
• Client Resync Handler
• 클라이언트가 보낸 해시와 서버가 계산한 해시가 다를 때 호출됨
1. 서버가 상태가 어긋난 Client Input Frame을 알려줌
2. Client Input History에서 해당 프레임부터 차례대로 적용 (Replay)
https://github.com/zeliard/PongRewind/blob/master/PongClient/PongClient/GUIController.cpp#L275
Server Logic
• Server Update Loop
1. 바로 이전 WorldFrame의 상태를 꺼내온다
2. ++WorldFrame
3. 월드 상태 업데이트
4. 업데이트된 월드 상태를 현재의 WorldFrame History에 저장
5. 클라이언트에 업데이트된 상태 방송
https://github.com/zeliard/PongRewind/blob/master/PongShared/GameLogic.cpp
Server Logic
• Server Receive Handler
• 클라이언트로부터 받은 정보에 포함된 WorldFrame 시점에서 판정
• 해당 시점으로 서버 되감기 한 후 시뮬레이션
• 시뮬레이션 결과 해시와 클라에서 보내온 해시와 다르면 Desync 상황
• 이 경우 클라이언트에게 알려서 Resync 요청
• 클라이언트의 입력을 반영
https://github.com/zeliard/PongRewind/blob/master/PongServer/PongServer/GameManager.cpp#L57
서버 되감기 부작용
• 최대 지연 시간만큼의 후판정으로 인한 불쾌감
• (예) 피격자가 엄폐물 뒤로 숨었는데 피격되는 일
• 지연은 제거할 수 없고, 다른 곳으로 숨길 수밖에 없기 때문
• 누구에게 더 좋은 느낌을 주도록 할까? 공격자 or 피격자?
• 일반적으로 FPS는 공격의 횟수가 피격의 횟수보다 절대적으로 많기 때문에…
• 현대의 FPS게임은 총 쏘는 사람 입장을 더 쾌적하게 하는 것을 주로 선택
서버 되감기 모범사례
• 월드 상태를 모두 되감기 할 것인가?
• 관련 있는 녀석(주로 Actor)만 되감기 하는 것이 일반적
• History를 얼마만큼 보관할 것인가?
• 보통은 서버/클라간 최대 Latency 안에서
• 빠른 (서버 클라간 RTT/2 이내에 판정이 나는) 무기에 적용
• 발사체(Projectile)은 전혀 다른 방식으로 접근해야 함*
• 되돌릴 수 없는 속성(Unrewindable Property) 지정
• 이미 서버에서 확정(commit)한 것들 (예: Alive, Score, …)
• Desync 상황 핸들링
• 따로 패킷으로 보내서 클라에게 Resync요청하기보다 주기적으로
방송하는 업데이트 패킷에 포함 하는 것이 좋음
월드 상태 방송시 고려사항
• 월드 상태 전송시 변화(delta)분만 보낼 것인가?
• 전체 데이터를 보내되 압축을 사용할 것인가?
• CPU 사용률은 높아지지만 네트워크 대역을 줄일 수 있음
(개인적인 경험으로는 600 bytes 이하면 패킷 압축은 크게 의미 없는 경우가 많았음)
• 프로토콜별 주의사항
• TCP: Nagle 알고리즘을 꺼야 하는 경우가 대부분
• UDP: 패킷 크기가 클수록 손실 확률이 높아짐
• 크기가 충분히 작다면(100 byte 이내) 이전 프레임의 데이터를 중복 포함해서 재전송 피하기
• Bit packing 최대한 활용
• 패킷이 MTU 경계에 걸릴 확률이 높으면 압축을 고려
Re:Wind
• 서버 되감기를 통한 동기화
• FPS게임에서는 이미 많이 쓰이고 있는 기술
• 기본적으로는 서버 동기화 기반 (A+P system)
• Lag으로 인한 불쾌함을 최소화 하기 위해 강한 일관성을 버리고
• 유저에게 최대한의 공정함을 주기 위해 최종 일관성을 흉내낸 방법
게임 로직과 결정성
(Determinism)
게임 로직과 결정성
• 결정형 (deterministic) 게임 로직
• 동일한 입력에 대해 항상 동일한 결과가 나올 수 있는 게임 로직
• 원격지간 동기화시 입력만 맞추면 동일한 결과 보장
• 동기화 설계가 쉬워질 수 있음을 의미
• (참고) deterministic physics*
• 랜덤의 요소가 존재한다면?
• (예) 스타크래프트의 해병 라이플 데미지가 6~10 랜덤일 경우
• 피격대상의 히드라 HP가 8 남은 상태라면?
• 어떤 경우에는 히드라가 살고, 어떤 경우에는 죽게 됨 (운빨 ㅈ망겜)
• 비결정성인 것 같지만…
난수와 결정성
• 사실 컴퓨터에서 생성하는 난수는 Pseudo Random Number
• 어떤 초깃값(SEED)를 이용하여 이미 만들어진 메커니즘을 통하여 생성되는
수로 무작위처럼 보이는 가짜 난수
• 즉, 초기 SEED 값만 같으면 똑같은 난수가 생성됨 (Deterministic!)
• 처음 SEED 동기화 후 각자 시뮬레이션해도 같은 결과(난수)가 나옴
사실 님들의 게임 운빨은 결정되어 있음
난수 동기화
• SEED만 맞추면 망고땡인가?
• 의사난수 생성기는 상태가 있음을 의미
• 호출 할 때마다 상태가 바뀜
• 직전에 생성된 난수의 일부를 SEED로 사용
• 즉, 랜덤 생성 함수 호출 과정(횟수)이 같아야 결정성이 보장됨
• 특정 서버(월드) 프레임 번호를 랜덤 SEED로 사용하면 난수 동기화가 쉬워짐
• 멀티스레드 게임 로직에서는 동일한 시뮬레이션 결과를 기대할 수 없음
• 스레드별로 PRNG를 둔다고 해도, 게임 로직이 여러 스레드에서 도는 경우
멀티스레드와 결정성
• 동일한 게임 로직을 멀티스레드의 형태로 처리한다면?
• Lock-Step 계열의 동기화가 가능한가? 서버 되감기시 문제 없는가?
• 게임 로직이 멀티스레드여야만 하는 경우는?
• 수만개의 액터를 동시에 시뮬레이션해야 하는 게임?
• A + P 시스템을 극단적으로 사용할 수밖에 없는 상황인 경우: MMORPG?
• 비결정성
• 똑같은 입력이 주어지더라도 다른 시뮬레이션 결과가 나올 수 있음
• 멀티스레드 게임로직은 정확히 어떤 순서로 실행될지 알 수 없음
• NP-Hard 문제 (웰컴투더헬: 최악의 경우 모든 가능성을 다 조사해봐야…)
부동소수점과 결정성
• 같은 물리 계산식인데 상대 플레이어 머신에서는 다른 결과가?
• 입력과 로직이 같은데 결과가 다르다? 흠좀무…
• 다음중 하나라도 어긋나면 부동소수점 결정성이 깨질 수 있음
• CPU 아키텍처, OS, 컴파일러 종류 및 최적화 수준, 빌드종류(debug/release)
• 특히 크로스플랫폼 멀티플레이 게임 제작시 주의 필요
메모리와 결정성
• 주소 값으로 인한 의도하지 않은 비결정성
• C++ STL 컨테이너 내의 정렬 문제
• default sort는 원래의 순서를 보존하지 않음 (cf: stable_sort)
• 주로 포인터 값을 기준으로 비교할 때 발생
• 포인터 값을 key로 사용하는 경우 항상 주의 (즉, 주소를 해시하는 경우)
• 초기화되지 않은 메모리가 결정성에 영향을 주는 경우
• struct의 경우 alignment에 의해 멤버 사이의 공간에 채워진 값이 다름
• Padding까지 깔끔하게 초기화 하기 위해서는 memset()
• 직접 바이너리 비교 또는 해시를 통한 정렬 주의
정리
• 최종 일관성은 유용한 도구의 하나
• No Silver Bullet
• 게임 특성에 따라 일관성 vs 가용성 선택
• 동시에 만족하는 경우는 없으니 과감히 포기
• 전송해야 하는 물리 상태의 양이 많다면 입력만으로 동기화가 가능한
lock-step이 유리하나, 그 이외의 경우에는 서버 동기화가 대부분 유리
• 동기화 메커니즘 설계시에는 항상 결정성을 고려
• 이도저도 귀찮으면 그냥 서버에서 모두 동기화하고 클라는 알아서 보정
참고 자료
• Dead Reckoning: https://en.wikipedia.org/wiki/Dead_reckoning
• Raft: https://raft.github.io/
• Paxos: https://en.wikipedia.org/wiki/Paxos_(computer_science)
• CAP theorem: https://people.eecs.berkeley.edu/~brewer/cs262b-2004/PODC-keynote.pdf
• PARCELC: https://en.wikipedia.org/wiki/PACELC_theorem
• NoSQL: https://www.slideshare.net/akleinbe/the-rise-of-nosql
• Eventual Consistency: https://en.wikipedia.org/wiki/Eventual_consistency
• Eventual Consistency for TERA : http://download.enmasse.com/documents/201205-gdm-tera.pdf
• Consistency Model: https://en.wikipedia.org/wiki/Consistency_model
• Lag Compensation: http://www.gamedonia.com/blog/lag-compensation-techniques-for-multiplayer-games-in-realtime
• NetCode for Overwatch: https://www.youtube.com/watch?v=vTH2ZPgYujQ https://www.youtube.com/watch?v=H0zbpPCdhGk
• Server Rewind for FPS Games: https://kotaku.com/5869564/networking-how-a-shooter-shoots
• Server Rewind for Projectiles:
https://www.gamasutra.com/blogs/NeemaTeymory/20160906/280377/Why_Making_Multiplayer_Games_is_Hard_Lag_Compensating_Weapons_in_M
echWarrior_Online.php
• Deterministic Physics: https://gafferongames.com/post/deterministic_lockstep/
• Floating-point Determinism: https://gafferongames.com/post/floating_point_determinism/
• Rollback Networking for Inversus: http://blog.hypersect.com/rollback-networking-in-inversus/
감사합니다.
이어지는 세션 광고
• 게임 동기화 자체에 대한 사례와 실전 팁들을 좀 더 알고 싶으시면
• 게임플레이 동기화 개론, 11시 국제회의장, 넥슨 송창규
• 이동/공격 동기화, 리얼타임 네트워킹, 해킹과 보안, 락스텝과 시뮬레이션
• 애니메이션/연출 그리고 조작감, Dedicated Server, 난입과 롤백
• CAP / NoSQL의 실전사례에 대해 관심 있으시면
• 듀랑고 / NoSQL위에서 MMORPG개발하기, 11시 1994홀, 넥슨 최호영
보너스
• Lock-Step은 점점 쓰이는 곳이 없지만
• 동기화에 관심 많은 분들은 직접 한 번 구현해보는 것이 많은 도움이 됨
• 많은 예외 상황에 대한 통찰을 주기도 하고
• 업계 신참들에게는 자신의 실력 향상을 위한 좋은 기회가 되기도 함
• 그래서, 준비했습니다: https://github.com/gasbank/laidoff
• 서버 되감기 또는 락스텝으로 고쳐볼 수 있는 장난감 프로젝트

Multiplayer Game Sync Techniques through CAP theorem

  • 1.
    Nexon OC Studio TechnicalDirector 구승모 최종 일관성, 서버 되감기 기법, 그리고 결정성에 관해 CAP 정리를 통한 게임 동기화 이야기
  • 2.
    • 캘리포니아 오랜지 카운티에위치 • 주로 Amazon, Blizzard, NC, Riot, Sony 출신의 개발진으로 구성 (이 게임 회사들 물리적으로 10분 이내에 위치…) • PC/Console • 주로 북미/유럽 대상
  • 3.
    발표자 소개 • NexonOC 테크니컬 디렉터 • WOW 때문에 인생 크게 바뀐 케이스 • 이 게임 때문에 게임 업계로 이직 • NCSOFT 서버 프로그래머 • Bluehole 선임 엔지니어 / 서버 아키텍트 • NHN NEXT 게임 전공 교수 • Amazon Games 수석 엔지니어 • NDC 2014 • “사설 서버를 막는 방법들“ (우수세션) 전투/작전 사령관 캐릭 하나씩, 오리지널 낙스라마스 공대 2005년에만 순수 게임 플레이 시간: 160+일
  • 4.
    목차 1. CAP 정리그리고 최종 일관성 2. 멀티플레이어 게임 동기화 101 3. 서버 되감기를 통한 동기화 4. 게임 로직과 결정성
  • 5.
    이 세션에서 다루지않는 것들 • 여러가지 Dead Reckoning 테크닉* • 분산 시스템에서의 합의 알고리즘 또는 상태 복제 프로토콜들* • PACELC 같은 CAP의 확장 정리* • 각종 일관성 모델* * 자세한 내용은 참고 자료 슬라이드에…
  • 6.
    CAP 정리 그리고최종 일관성
  • 7.
    CAP Theorem • 2000년,Eric Brewer* • 튼튼한(robust) 분산 시스템 설계시 기술적인 선택에 도움을 주는 정리 • 일관성 (Consistency) • 가용성 (Availability) • 분할용인 (Partition Tolerance) • C+A+P를 동시에 모두 만족하는 시스템은 없음 • 2개 선택하세요 • NoSQL과는 사실상 관련 없음 IMG From: https://docs.deistercloud.com/Technology.50/NoSQL/index.xml
  • 8.
    NoSQL • 대량의 데이터를빠르게 처리하기 위함 • 데이터간 관계가 단순 • Schemaless • Key-Value, Key-Document 형태가 일반적 • 단순하지만 고성능 및 고가용성을 제공 • 내부적으로 스토리지 구조가 샤딩 및 복제본을 두는 형태 • 실전에서 많이 사용되는 것들* • MongoDB, Cassandra, DynamoDB, … Node1 Node2 Node3 Client1 Client2 비동기 업데이트 Writes Read
  • 9.
    AWS DynamoDB 예 •DynamoDB의 데이터 읽기/쓰기 • Write는 3군데의 스토리지에 분산 복제 저장 (2군데 쓰면 바로 응답리턴) • Read는 2가지 방법 중 선택 • Default Read: 3개의 노드중 가장 먼저 응답하는 하나에서 읽기. 이 경우 과거의 데이터를 읽어올 가능성이 있음 (가용성을 선택) • Consistent Read: 모든 노드의 데이터가 동기화된 후에 읽어옴 (일관성 선택) Client1  DynamoDB Storage (3벌 복제 및 분산 저장) Client2 Client3 Read ReadWrite  Client2와 Client3은 서로 다른 상태를 볼 수 있음
  • 10.
    최종 일관성 (EventualConsistency) • A+P 시스템 기반위에 뒤늦게 일관성을 맞추는 방식* • 순간적으로 과거의 데이터를 볼 수 있지만, 결국 일관성이 맞춰짐 • (참고) AP 시스템이라고 해서 최종 일관성을 무조건 만족하는 것은 아님 (e.g.) AWS SQS IMG From: http://www.cloudcomputingpatterns.org/eventual_consistency/
  • 11.
    멀티스레드 환경에서의 일관성 •싱글스레드 • C + A: 일관성(C) + I/O 등으로 인한 블로킹이 없다면 (A) • Lock으로 동기화하는 멀티스레드 환경 • C + P: 잠금을 통한 일관성 유지 (C) + 멀티스레드 (P) • 여러 스레드가 항상 동일한 공유자원 상태를 볼 수 있음 (Consistency) • 이 방법은 Availability가 보장되는가? • 하나의 스레드가 잠금 중일때는 다른 모든 스레드는 대기해야 함 (순간적으로 Available하지 않음을 의미) • Lock안에서 I/O등을 통한 대기가 걸린다면? Lock Convoying…
  • 12.
    최종 일관성을 통한멀티스레드 성능 향상 • 일관성을 약간(?) 양보할 수 있는 경우 • 특정 스레드가 과거의 상태를 잠깐 보는 한이 있어도 스레드가 공유자원 접근시 대기하지 않도록 함 • C + P 대신 C + A를 선택 • 대신, 결국에는 모든 스레드가 같은 상태로 맞춰질 수 있도록 구현 • How-to • Thread Local Storage별 자료구조를 두고 업데이트 큐(lock-free or wait- free queue)를 활용하여 스레드별 업데이트 • 읽기는 스레드 로컬 접근, 업데이트는 큐를 활용하여 비동기적으로 • (예) https://github.com/zeliard/Dispatcher/blob/LB_version/JobDispatcher/LoadBalancer.h
  • 13.
    TERA Case Study •처음에는, 하나의 맵을 두고 여러 로직 스레드가 경합 • ReadLock을 통한 검색, WriteLock을 통한 업데이트 • 모든 스레드가 동일한 맵 상태를 볼 수 있지만 (일관성 유지)  CPU 100% !! Actor 11 12 13 21 22 23 31 32 33 Map C C’ Worker Thread #1 Waiting… Worker Thread #2 Lock – Update - Unlock Worker Thread #n Waiting…
  • 14.
    Update Queue U (1) Push Map UpdateTask 0 N 1 2 3 … Queue Index Replicated Map Info Thread Local Map 1 Thread Local Map 2 Thread Local Map N Sequence of Task Execution (2) Pop & Execute Update Task U D D Current TLS index: 2Current TLS index: 1 Current TLS index: 1 Current TLS index: 1 Current TLS index: 2 Current TLS index: 2 D TLS를 이용한 최종 일관성으로 변경 순간적으로 특정 스레드는 과거의 상태를 볼 수 있지만 Lock 경합이 없음  스레드 입장에서는 맵 자료구조가 언제나 가용(available)한 상태  성능 향상
  • 15.
  • 16.
    싱글 플레이어 게임의처리 과정 Inputs Simulate Render Wait States events timer State State State Time Frame Per Second (FPS)  이 루프가 1초에 몇 번 도는가? C + A 시스템
  • 17.
    멀티 플레이어 게임동기화 타입 동기형 (타입1)비동기형 동기형 (타입2)
  • 18.
    비동기형 (Asynchronous) 게임 •주로 웹서비스 형태의 백엔드 • 2-tier: web servers + data store • 3-tier: web front + app servers + data store • HTTPS를 이용한 보안성 확보가 쉬움 • 연결 유지가 필요 없어 접속이 불안정한 환경에서 유리 • 모바일 게임 및 소셜 게임 장르에 적합 • (요즘 대세) 서버리스 형태로도 백엔드 구축 가능 • API Gateway, Cloud function, Lambda, … Client LB Web Server Browser Web Server Client Browser Web ServerHTTP
  • 20.
    비동기형 게임의 일반적인동기화 방식 Request/Response 구조 • 웹의 특징을 그대로 물려 받음 • Atomic, Stateless • 플레이어간 순서 보장이 필요할 경우 • 사과를 친구가 먼저 수확한 경우 어떻게 처리? • 주로 캐시서버나 DB에서 동기화 • 수동적: Server-initiated Action 어려움 • 몬스터의 선공과 같은 능동적 NPC 행동 불가 Client Web Server State State State Response Request
  • 21.
    동기형(Synchronous) 게임 • 실시간동기화 • 멀티플레이어 게임도 하나의 분산 시스템이라고 볼 수 있음 • 사실 CAP는 분산 시스템 어디서나 적용할 수 있는 이야기 • 원격지의 상태 복제를 통해 동기화 • 게임 스타일에 따라 일관성과 가용성 중 선택해야 함 • 네트워크 게임 == 분산 환경 (즉, P는 필수 요소) • 선택지: 가용성(A) vs 일관성(C)
  • 22.
    • 서버가 게임로직 처리(Simulate) 및 동기화 • 클라이언트는 서버를 통한 간접 연결 • NPC를 서버가 능동적으로 활용(drive)할 수 있음 • 주로 사용되는 장르: FPS, MMORPG, MOBA, Sports 동기형 (타입1: 서버 동기화) Simulate States Inputs Render Wait eventsServer state info
  • 24.
    • Client-Server 아키텍처 •클라이언트에서 발생하는 이벤트는 서버에서 모두 모아 계산한 후 클라이언트로 방송 • 자본주의(?) 동기화 / 낙관적(?) / A+P System • 서버가 먼저 진행  클라는 따라올테면 따라와봐  네트워크 속도가 빠른 클라일수록 서버와의 격차가 가장 적음 (유리) • 서버/클라간 시간차는 클라가 알아서 Dead Reckoning* Server Client A Client B NPC NPC NPC A B A A B B Event A Event BNPC Event 서버 동기화 (Server-Authoritative) 클라가 늦게 받을수록 튀는 현상 발생
  • 25.
  • 26.
    서버 동기화 TickRate고려사항 • 서버 시뮬레이션 TickRate 및 방송 주기는 얼마로 할 것인가? • 높은 TickRate는 더 정확한 판정 (이후 설명할 서버 되감기에도 더 유리) • 그러나 더 많은 CPU와 네트워크 대역을 요구 (인프라 비용 상승) • (예) 고오급시계의 기본 서버 방송 주기는 20Hz, 커스텀 모드는 60Hz 까지
  • 27.
    방송 범위와 보안 •시야 범위 (Area Of Interest) • AOI 관리를 통해서 클라가 알아야 하는 범위의 정보만 전송 • (참고) UE4 Dedicated Server의 Network Relevance • AOI 범위가 좁을수록 플레이어 경험이 불쾌해짐 (시야가 좁아짐) • AOI 범위가 넓을수록 패킷 처리량이 많아지고 보안에 불리해짐 • (예) PUBG • 원거리 저격 때문에 멀리 있는 적 정보까지 동기화 대상 • 벽뒤에서 갑툭튀(?) 때문에 AOI Occlusion Culling을 적용하기도 어려움
  • 28.
    • 상대 플레이어로부터주기적으로 이벤트를 모아 각자 시뮬레이션 • RTS 및 과거의 AOS 장르에서 주로 사용 동기형 (타입2: Lock-Step 동기화) Inputs Simulate Render Wait States peer events Inputs Simulate Render Wait States Compare Compare Same hashval?
  • 29.
    Dropped from thegame? IMG From: http://starcraft.burningblade.org/stories/index.html
  • 30.
    Lock-Step 형태의 동기화방식 • 각각의 클라이언트는 모두 아래와 같은 형태의 Queue를 유지 • 공산주의(?) 동기화 / 비관적(?) / C+P System • 다 함께 같이 간다  클라가 하나라도 멈추면 다 같이 기다린다 • 서버 동기화 방식과 다르게 특정 클라만 튀는 현상 없음 • 월드의 전체 내용을 서로 공유하기 때문에 해킹에 취약 (맵핵/헬퍼) • 라운드간 Lag 숨기기 기법을 최대한 활용*: (예) 스타크 마린의 Pre-Anim & Sound play events eventsevents나 상대1 상대2 Round 0 ms 50 100 150 Round Round Round events events events 모든 Peer들의 입력이 모이면 해당 Round를 처리(Simulate) 하고 렌더링 특정 Peer의 정 보가 제시간에 도달하지 않으 면 Block ?? events
  • 31.
  • 32.
    Lock-Step 동기화 TickRate고려사항 • Lock-Step 동기화 주기(Round 길이)에 영향 • 스타크래프트 Low/High latency 옵션 예 • Low: Waiting for players 화면을 볼 가능성이 더 높지만 반응성이 더 좋음 • TickRate 높고, Round 길이 짧음 • High: 게임은 더 부드럽게 진행되지만 반응성이 더 느림 • TickRate 낮고, Round 길이 김 • (예) CR게임 동기화 • 글로벌 원 서버 (A社 미국 클라우드) • 1초 Round 동기화: 지구 반바퀴 지연 0.5s 이내
  • 33.
    Re:CAP • 서버 동기화 •A+P System: 플레이어들에게 랙없는 경험을 최대한 주기 위해 항상 응답 가능한 상태(Available)를 유지 • Lock-Step 동기화 • C+P System: 플레이어들에게 공평한 경험을 주기 위해 항상 일관성(Consistent)이 있는 상태를 유지
  • 34.
  • 35.
    왜 Lag을 보정해야하는가? • 인터넷은 빨라졌지만… • 멀티플레이어 게임에 국경이 없어지고 있음 • 글로벌 원빌드, 더 먼거리의 플레이어간 대전 • 역설적으로 플레이어들은 랙에 노출이 더 심해짐 • 결국 랙을 핸들링 해야 함 • 가까운 거리상의 플레이어들끼리 매칭하도록 강제하거나, • 랙을 무시하고 클라이언트가 최대한 알아서 보정 하거나, • 게임 시스템이 알아서 보정해주는 트릭을 사용해서 플레이어를 속이거나(?)
  • 36.
    동기화 트렌드 • 어차피Lag을 피할 수 없다면… • 일관성을 맞추기 위해 누군가를 기다려야 한다는 것은 불쾌한 경험을 줌 • CP 시스템은 아주 제한적으로 사용 가능 (예: Round주기가 500ms 이상) • 최악의 경우에도 Round 주기 이내에 응답이 오는 경우를 가정 • 누군가를 기다리지 않는 서버 동기화의 방식을 채택 (AP 시스템) • 여기에 최종 일관성을 통한 최대한의 공정함을 보장하는 방법 사용 • 공정한 플레이 및 쾌적한 느낌을 주기 위해 Lag을 보정 • 서버 되감기를 통한 동기화*
  • 37.
    서버 되감기를 통한동기화 • 서버는 클라이언트가 보던 과거의 시점으로 돌려서 판정 • 퀘이크, 듀크뉴캠, 콜오브듀티 등이 이 방법 사용 • 게임 시뮬레이션은 서버와 클라이언트에서 모두 각자 함 • 클라이언트의 입력 및 자체 시뮬레이션 결과를 서버에 전송 • 서버에서 클라이언트의 입력 시점으로 되돌려서 시뮬레이션 • 클라에서 보내준 자체 시뮬레이션 결과와 같다면 OK • 클라에서 보내준 자체 시뮬레이션 결과와 다르다면 클라이언트에게 알려줌 • 서버에서의 최종 결과가 도착하면 클라이언트에서 보정 • 클라에서 예측을 통한 시뮬레이션을 먼저 하고 진행하는 것이 일반적 • 예: LOL의 틱당 골드 증가
  • 38.
    서버 되감기 시각화 IMGFrom: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking
  • 39.
    아주 쉬운 예 •울트라 캡숑 쉬운 예제: Pong Laser 게임 P2 P1 Shoot a Laser Game World
  • 40.
    기본 원리 TIME CLIENT SERVER Latency Shoot TargetHit Target Move Target Move Shoot Target Hit Target Hit? Target Hit Approved Server Rewind
  • 41.
    상태 변화 요약 •서버가 클라에게 보낸 월드 상태 • 클라가 서버에게 보낸 입력 변화 WorldFrame TARGET PosY 1 2.0 2 3.0 3 5.0 4 8.0 WorldFrame Client Input FR Shoot 1 1 No 2 2 No 2 3 No 3 4 Yes 클라이언트가 알고 있는 WorldFrame 기준으로 서버가 상태를 되돌려 판정
  • 42.
    Real Code Sample •Pong Laser • https://github.com/zeliard/PongRewind • 일부러 서버/클라이언트 양측에 랜덤 Delay를 넣어서 Desync상황 연출 최대한 쉽고 깔끔하게 만드려고 노력했으나 급하게 만든 날코딩 양해 구함
  • 43.
    Pseudo Code Level •클라이언트가 보내는 정보 Client Input (Request) • 서버가 방송하는 정보 Game Status (Broadcast)
  • 44.
    서버 되감기를 위한히스토리 유지하기 • 서버측에서 WorldFrame별 상태 보관 • 과거의 상태가 필요한 오브젝트에 대해 WorldFrame(서버프레임)별 스냅샷 • 참고: 이번 예제는 너무 간단하므로 월드 상태를 통째로 유지함 • 실전에서는 되감기가 필요한 객체에 대해서만 제한적으로 유지하는 것을 추천
  • 45.
    • Client UpdateLoop 1. 현재 플레이어의 입력을 얻는다 2. 플레이어 입력을 기반으로 시뮬레이션(상태 업데이트)을 한다 3. 업데이트된 상태에 대한 해시를 구한다 4. 서버에 플레이어의 입력 및 해시 값을 보낸다 5. 클라이언트 입력에 대한 History를 기록한다 • Desync시 클라이언트 Replay를 위해 Client Input Frame 단위로 보관 Client Logic https://github.com/zeliard/PongRewind/blob/master/PongClient/PongClient/GUIController.cpp#L145-L164
  • 46.
    Client Logic • ClientReceive Handler 1. 서버로부터 도착한 최신 상태를 덮어쓴다 • 최신의 서버 상태로 강제 업데이트를 의미하나 바로 렌더링에 반영할지, 클라이언트에서 더 부드럽게 보정(데드레커닝)을 할지는 선택의 문제 https://github.com/zeliard/PongRewind/blob/master/PongClient/PongClient/GUIController.cpp#L233 • Client Resync Handler • 클라이언트가 보낸 해시와 서버가 계산한 해시가 다를 때 호출됨 1. 서버가 상태가 어긋난 Client Input Frame을 알려줌 2. Client Input History에서 해당 프레임부터 차례대로 적용 (Replay) https://github.com/zeliard/PongRewind/blob/master/PongClient/PongClient/GUIController.cpp#L275
  • 47.
    Server Logic • ServerUpdate Loop 1. 바로 이전 WorldFrame의 상태를 꺼내온다 2. ++WorldFrame 3. 월드 상태 업데이트 4. 업데이트된 월드 상태를 현재의 WorldFrame History에 저장 5. 클라이언트에 업데이트된 상태 방송 https://github.com/zeliard/PongRewind/blob/master/PongShared/GameLogic.cpp
  • 48.
    Server Logic • ServerReceive Handler • 클라이언트로부터 받은 정보에 포함된 WorldFrame 시점에서 판정 • 해당 시점으로 서버 되감기 한 후 시뮬레이션 • 시뮬레이션 결과 해시와 클라에서 보내온 해시와 다르면 Desync 상황 • 이 경우 클라이언트에게 알려서 Resync 요청 • 클라이언트의 입력을 반영 https://github.com/zeliard/PongRewind/blob/master/PongServer/PongServer/GameManager.cpp#L57
  • 49.
    서버 되감기 부작용 •최대 지연 시간만큼의 후판정으로 인한 불쾌감 • (예) 피격자가 엄폐물 뒤로 숨었는데 피격되는 일 • 지연은 제거할 수 없고, 다른 곳으로 숨길 수밖에 없기 때문 • 누구에게 더 좋은 느낌을 주도록 할까? 공격자 or 피격자? • 일반적으로 FPS는 공격의 횟수가 피격의 횟수보다 절대적으로 많기 때문에… • 현대의 FPS게임은 총 쏘는 사람 입장을 더 쾌적하게 하는 것을 주로 선택
  • 50.
    서버 되감기 모범사례 •월드 상태를 모두 되감기 할 것인가? • 관련 있는 녀석(주로 Actor)만 되감기 하는 것이 일반적 • History를 얼마만큼 보관할 것인가? • 보통은 서버/클라간 최대 Latency 안에서 • 빠른 (서버 클라간 RTT/2 이내에 판정이 나는) 무기에 적용 • 발사체(Projectile)은 전혀 다른 방식으로 접근해야 함* • 되돌릴 수 없는 속성(Unrewindable Property) 지정 • 이미 서버에서 확정(commit)한 것들 (예: Alive, Score, …) • Desync 상황 핸들링 • 따로 패킷으로 보내서 클라에게 Resync요청하기보다 주기적으로 방송하는 업데이트 패킷에 포함 하는 것이 좋음
  • 51.
    월드 상태 방송시고려사항 • 월드 상태 전송시 변화(delta)분만 보낼 것인가? • 전체 데이터를 보내되 압축을 사용할 것인가? • CPU 사용률은 높아지지만 네트워크 대역을 줄일 수 있음 (개인적인 경험으로는 600 bytes 이하면 패킷 압축은 크게 의미 없는 경우가 많았음) • 프로토콜별 주의사항 • TCP: Nagle 알고리즘을 꺼야 하는 경우가 대부분 • UDP: 패킷 크기가 클수록 손실 확률이 높아짐 • 크기가 충분히 작다면(100 byte 이내) 이전 프레임의 데이터를 중복 포함해서 재전송 피하기 • Bit packing 최대한 활용 • 패킷이 MTU 경계에 걸릴 확률이 높으면 압축을 고려
  • 52.
    Re:Wind • 서버 되감기를통한 동기화 • FPS게임에서는 이미 많이 쓰이고 있는 기술 • 기본적으로는 서버 동기화 기반 (A+P system) • Lag으로 인한 불쾌함을 최소화 하기 위해 강한 일관성을 버리고 • 유저에게 최대한의 공정함을 주기 위해 최종 일관성을 흉내낸 방법
  • 53.
  • 54.
    게임 로직과 결정성 •결정형 (deterministic) 게임 로직 • 동일한 입력에 대해 항상 동일한 결과가 나올 수 있는 게임 로직 • 원격지간 동기화시 입력만 맞추면 동일한 결과 보장 • 동기화 설계가 쉬워질 수 있음을 의미 • (참고) deterministic physics* • 랜덤의 요소가 존재한다면? • (예) 스타크래프트의 해병 라이플 데미지가 6~10 랜덤일 경우 • 피격대상의 히드라 HP가 8 남은 상태라면? • 어떤 경우에는 히드라가 살고, 어떤 경우에는 죽게 됨 (운빨 ㅈ망겜) • 비결정성인 것 같지만…
  • 55.
    난수와 결정성 • 사실컴퓨터에서 생성하는 난수는 Pseudo Random Number • 어떤 초깃값(SEED)를 이용하여 이미 만들어진 메커니즘을 통하여 생성되는 수로 무작위처럼 보이는 가짜 난수 • 즉, 초기 SEED 값만 같으면 똑같은 난수가 생성됨 (Deterministic!) • 처음 SEED 동기화 후 각자 시뮬레이션해도 같은 결과(난수)가 나옴 사실 님들의 게임 운빨은 결정되어 있음
  • 56.
    난수 동기화 • SEED만맞추면 망고땡인가? • 의사난수 생성기는 상태가 있음을 의미 • 호출 할 때마다 상태가 바뀜 • 직전에 생성된 난수의 일부를 SEED로 사용 • 즉, 랜덤 생성 함수 호출 과정(횟수)이 같아야 결정성이 보장됨 • 특정 서버(월드) 프레임 번호를 랜덤 SEED로 사용하면 난수 동기화가 쉬워짐 • 멀티스레드 게임 로직에서는 동일한 시뮬레이션 결과를 기대할 수 없음 • 스레드별로 PRNG를 둔다고 해도, 게임 로직이 여러 스레드에서 도는 경우
  • 57.
    멀티스레드와 결정성 • 동일한게임 로직을 멀티스레드의 형태로 처리한다면? • Lock-Step 계열의 동기화가 가능한가? 서버 되감기시 문제 없는가? • 게임 로직이 멀티스레드여야만 하는 경우는? • 수만개의 액터를 동시에 시뮬레이션해야 하는 게임? • A + P 시스템을 극단적으로 사용할 수밖에 없는 상황인 경우: MMORPG? • 비결정성 • 똑같은 입력이 주어지더라도 다른 시뮬레이션 결과가 나올 수 있음 • 멀티스레드 게임로직은 정확히 어떤 순서로 실행될지 알 수 없음 • NP-Hard 문제 (웰컴투더헬: 최악의 경우 모든 가능성을 다 조사해봐야…)
  • 58.
    부동소수점과 결정성 • 같은물리 계산식인데 상대 플레이어 머신에서는 다른 결과가? • 입력과 로직이 같은데 결과가 다르다? 흠좀무… • 다음중 하나라도 어긋나면 부동소수점 결정성이 깨질 수 있음 • CPU 아키텍처, OS, 컴파일러 종류 및 최적화 수준, 빌드종류(debug/release) • 특히 크로스플랫폼 멀티플레이 게임 제작시 주의 필요
  • 59.
    메모리와 결정성 • 주소값으로 인한 의도하지 않은 비결정성 • C++ STL 컨테이너 내의 정렬 문제 • default sort는 원래의 순서를 보존하지 않음 (cf: stable_sort) • 주로 포인터 값을 기준으로 비교할 때 발생 • 포인터 값을 key로 사용하는 경우 항상 주의 (즉, 주소를 해시하는 경우) • 초기화되지 않은 메모리가 결정성에 영향을 주는 경우 • struct의 경우 alignment에 의해 멤버 사이의 공간에 채워진 값이 다름 • Padding까지 깔끔하게 초기화 하기 위해서는 memset() • 직접 바이너리 비교 또는 해시를 통한 정렬 주의
  • 60.
    정리 • 최종 일관성은유용한 도구의 하나 • No Silver Bullet • 게임 특성에 따라 일관성 vs 가용성 선택 • 동시에 만족하는 경우는 없으니 과감히 포기 • 전송해야 하는 물리 상태의 양이 많다면 입력만으로 동기화가 가능한 lock-step이 유리하나, 그 이외의 경우에는 서버 동기화가 대부분 유리 • 동기화 메커니즘 설계시에는 항상 결정성을 고려 • 이도저도 귀찮으면 그냥 서버에서 모두 동기화하고 클라는 알아서 보정
  • 61.
    참고 자료 • DeadReckoning: https://en.wikipedia.org/wiki/Dead_reckoning • Raft: https://raft.github.io/ • Paxos: https://en.wikipedia.org/wiki/Paxos_(computer_science) • CAP theorem: https://people.eecs.berkeley.edu/~brewer/cs262b-2004/PODC-keynote.pdf • PARCELC: https://en.wikipedia.org/wiki/PACELC_theorem • NoSQL: https://www.slideshare.net/akleinbe/the-rise-of-nosql • Eventual Consistency: https://en.wikipedia.org/wiki/Eventual_consistency • Eventual Consistency for TERA : http://download.enmasse.com/documents/201205-gdm-tera.pdf • Consistency Model: https://en.wikipedia.org/wiki/Consistency_model • Lag Compensation: http://www.gamedonia.com/blog/lag-compensation-techniques-for-multiplayer-games-in-realtime • NetCode for Overwatch: https://www.youtube.com/watch?v=vTH2ZPgYujQ https://www.youtube.com/watch?v=H0zbpPCdhGk • Server Rewind for FPS Games: https://kotaku.com/5869564/networking-how-a-shooter-shoots • Server Rewind for Projectiles: https://www.gamasutra.com/blogs/NeemaTeymory/20160906/280377/Why_Making_Multiplayer_Games_is_Hard_Lag_Compensating_Weapons_in_M echWarrior_Online.php • Deterministic Physics: https://gafferongames.com/post/deterministic_lockstep/ • Floating-point Determinism: https://gafferongames.com/post/floating_point_determinism/ • Rollback Networking for Inversus: http://blog.hypersect.com/rollback-networking-in-inversus/
  • 62.
  • 63.
    이어지는 세션 광고 •게임 동기화 자체에 대한 사례와 실전 팁들을 좀 더 알고 싶으시면 • 게임플레이 동기화 개론, 11시 국제회의장, 넥슨 송창규 • 이동/공격 동기화, 리얼타임 네트워킹, 해킹과 보안, 락스텝과 시뮬레이션 • 애니메이션/연출 그리고 조작감, Dedicated Server, 난입과 롤백 • CAP / NoSQL의 실전사례에 대해 관심 있으시면 • 듀랑고 / NoSQL위에서 MMORPG개발하기, 11시 1994홀, 넥슨 최호영
  • 64.
    보너스 • Lock-Step은 점점쓰이는 곳이 없지만 • 동기화에 관심 많은 분들은 직접 한 번 구현해보는 것이 많은 도움이 됨 • 많은 예외 상황에 대한 통찰을 주기도 하고 • 업계 신참들에게는 자신의 실력 향상을 위한 좋은 기회가 되기도 함 • 그래서, 준비했습니다: https://github.com/gasbank/laidoff • 서버 되감기 또는 락스텝으로 고쳐볼 수 있는 장난감 프로젝트