728x90
게임서버
실시간 게임 최적화 전략
- 수동적인 서버
- 결과만 저장해주는 서버
- 패킷 중계
- 능동적인 서버 - 일반적인 게임서버
- 생태를 서버의 메모리에 저장하고 있다.
- DB는 보조 수단이다.
- 클라이언트의 시간 차 0을 목표로 한다.(불가능 하지만)
- 게임 루프가 있다.
- 서버가 하는 일 in Voxel Horizon
- 유저로부터의 패킷에 의한 이벤트처리
- 플레이어 or NPC에 대한 이동처리
처리량과 응답성의 차이
- 어느 부분이 문제인지 생각할 필요가 있다.
응답성 향상을 위한 주요 기법
- 비동기 처리
- 특정 작업 때문에 전체 응답성이 떨어지는 상황을 방지
- 멀티 스레드 - 별도의 worker thread가 처리
- 싱글 스레드 - 작업을 쪼개서 원래의 작업 스레드에서 여러번에 걸쳐서 처리
- thread pool을 이용한 병렬처리
- 서로 의존성을 가지지 않는 n개의 항목에 대해 M개의 worker thread가 병렬로 처리한다.
- thread pool이 작업을 완료 할 때 까지 원래의 작업 스레드는 대기한다.
- 코드 최적화 - SIMD 등
- 서로 조합해서 사용 가능하다.
비동기 처리
- 로그인/로그아웃
- 급하지 않은 작업
- 특정 작업 때문에 전체 응답성이 떨어지는 상황을 방지한다.
- DB 종속적인 작업들
- 저장소에 대한 I/O
비동기 처리 - 싱글 스레드
- 별도의 worker thread를 생성하지 않는다.
- 긴 시간이 걸리는 작업을 쪼개서 메인 스레드의 타임 라인에 분산해서 처리한다.
- 시간 전체 처리 소요 시간은 그대로, 처리까지 걸리는 시간은 상승, 응답성은 상승
- 스레드 간 동기화가 복잡해질 경우 선택한다.
- 스레드간 동기화 비용 0
- 메인 스레드의 응답성은 약간 저하 될 수 있다.
비동기 처리 - 멀티 스레드
- 별도의 worker thread에 작업을 할당하여 완전히 백그라운드로 작업
- 남는 CPU자원을 조금이라도 더 사용할 수 있다.
- worker thread로 작업을 넘겼을 때 필요한 자원도 완전히 분리할 수 있을 경우(동기화 부담이 없을 경우)에 적합하다.
- 메인 스레드 응답성에 거의 영향을 끼치지 않는다.
- 스레드 동기화 비용이 아주 적을 경우만 사용해야 한다.
Thread Pool을 이용한 병렬처리
- 1차선 도로를 N차선 도로로 확장
- 처리량 때문에 지연이 발생하는 경우 사용
- 처리해야 할 항목(원소) 각각이 서로 의존성이 거의 없어야 함
- thread per core일 때,(이론상) 거의 선형적으로 처리량 증가
- 비동기 처리와 병행 가능
코드 최적화 - SIMD등
- 당장 수행되어야 할 코드
- 컨텍스트 스위칭 없이 현재 컨텍스트 상에서 당장 빠르게 코드에 실행되어야 하는 경우
- thread pool을 쓰는 경우 thread pool이 작동하기 시작해서 결과를 동기화할 때 까지의 비용이 더 클 수 있다.
- 그냥 정직하게 빠른 코드를 짜야한다.
- 수학 연산이 많다면 SIMD는 반드시 사용한다.
- STL을 걷어내고 직접 짜게되면 보통 빨라진다.
응답성 향상을 위한 코딩
- 범용 Heap 보다는 Stack을 사용
- 범용 Heap보다는 고정 사이즈 memory pool(병합기능 x)
- 적절한 동기화 객체 선택
- SIMD 최적화의 경우 전체적으로 최대 30%까지 성능 향상을 기대할 수 있다.
실제 게임서버에 적용
VOXEL Horizon에서의 사례
기본전략
- 응답성 최우선
- 1개의 메인스레드 + n개의 보조 스레드 풀
- 동기화로 인한 성능 저하 방지
- 유지보수 용이(디버깅, 후임자 인수인계)
- 클라이언트와 서버가 대부분의 코드를 공유할 것
- 동일 입력 동일 결과 보장
- 유지보수 용이
- 멀티 스레드 남용 금지!
- 가능하면 SIMD 사용 → 그러나 큰 기대는 금물
서버와 클라이언트의 코드 공유
- 클라이언트와 서버는 최대한 코드를 공유한다.
- 서버와 클라이언트가 동일한 입력에 대해 동일한 결과를 보장
- 엔진 코드는 서버에서도 그대로 사용하므로 서버에서 필요한 기능을 지원할 것
- 다수의 인스턴스 생성
- 멀티 스레드를 이용한 병렬 처리
- 비동기 처리
서버의 작업 스케쥴링 전략
- 1개의 메인 스레드 + N개의 보조 스레드 풀
- 동기화로 인한 성능 저하 방지
- 유지보수 용이
- 메인 스레드의 명령에 의해 다수의 워커 스레드가 작업
- 작업을 마치면 워커 스레드가 메인 스레드에 통보
패킷 수신 → 메시지 처리
- 최소 패킷 구조 = SIZE(4 bytes) + Body(N bytes)
- I/O 워커 스레드의 메시지 수집과 메인 스레드의 경쟁 상태를 줄인다.
- Double buffering
- 하나 이상의 패킷이 수집되면 network 측 worker thread가 쓰기 버퍼에 수집된 패킷을 써넣는다.
- main thread는 패킷 수신이 통보되면 쓰기 버퍼와 읽기 버퍼의 포인터를 swap한다(가벼운 lock사용)
- main thread는 읽기 버퍼의 쌓인 패킷을 처리한다.
- 처리가 완료되면 쓰기 버퍼와 읽기 버퍼의 포인터를 swap한다.
서버에서의 이동(충돌)처리
- 클라이언트와 마찬가지로 30fps or 60fps로 처리
- 키 입력에 대한 순서가 보장되어야 한다.
- 플레이어간 입력 순서가 보장되어야 한다.
- 따라서 완전 동기식으로 처리하되 개별 이동처리 시간을 줄이는 수밖에 없다.
- 처리해야할 캐릭터 수에 비례해서 성능이 하락한다.
- 처리량이 늘어서 응답성이 떨어지는 경우이므로 thread pool을 이용하여 병렬처리를 한다.
전투판정
- 로켓의 유도 , 타격은 캐릭터 이동(충돌)처리와 동일하다.
- gun 타입의 무기들은 총구로부터의 ray가 존재한다.
- ray와 지형/캐릭터의 충돌처리가 사실상의 전투판정이다.
- 다수의 삼각형(복셀지형)/타원체에 대한 수학연산이 필요하다.
- 총을 들고 있는 플레이어/npc의 수가 증가하면 당연히 소요시간이 길어진다.
- 이동(충돌)처리와 마찬가지로 thread pool을 이용한 병렬처리를 사용한다.
복셀 데이터 압축 전략
- thread pool을 이용한 병렬처리
- 코드 최적화
- 싱글 스레드로 비동기 처리
- 복셀 편집 이벤트가 발생한 경우
- 무기에 의한 파괴/복셀 추가/색상 변경/ 삭제/ 정밀도 변경 등
- 압축 대기 목록에 추가 ← lazy loading 비슷해보였다.
- 플레이어의 위치 변경에 의해 복셀데이터를 전송해야하는 순간까지 압축처리를 하지 못한 경우, 해당 오브젝트는 그 즉시 압축
개인맵 로드/세이브
- 플레이어가 자신의 개인맵에 들어가려고 할 경우 파일로부터 개인맵을 읽어야 한다. 처음 들어가는 경우 새로 생성해야 한다.
- 플레이어가 개인맵에서 나갈 경우 개인맵을 저장해야한다.
- 디스크 I/O가 발생하므로 느리다.(메모리 연산의 지연시간과 차원이 다르다)
- 다수의 유저가 동시 다발적으로 개인맵에 들어가거나 나갈 경우 메인 스레드의 응답성이 크게 저하될 수 있다.
비동기 DB 쿼리
- DB에 쿼리 후 응답 수신 후 메모리에 업데이트
- 로그인, 아이템 획득 등
- 서버의 메모리 업데이트 후 DB에 쿼리(저장)
- 총알 소모, 캐릭터 데이터 세이브, 기타 등등
- 어느쪽이든 비동기 처리
- 절.대.로 DB의 게임서버의 패킷 처리 스레드가 DB의 응답을 대기해서는 안된다.
멀티 스레드가 능사가 아니다
- 동기화 비용은 생각보다 크다
- 초기 코딩의 어려움
- 디버깅의 어려움
- 유지보수의 어려움
- 처리량의 한계로 응답성이 떨어지는 경우만 사용할 것
- 활성화된 core 개수에 따라 turbo boost가 꺼지므로 예상보다 더 성능이 안나온다.
결론
- 처리량에서의 병목으로 응답성이 떨어지는가?
- thread pool을 이용한 병렬 처리
- 당장 처리할 필요가 있는가?
- 당장 처리할 필요가 없으면 비동기 처리
- 메인 로직과 분리할 수 있는가? → 별도의 스레드를 사용하는 비동기 처리
- 당장 처리해야 하고 병렬화가 어려울 경우
- 코드 최적화
- 읽기 전용 메모리는 공유, 쓰기가 발생하는 경우 copy-on-write 적용
참조
https://www.youtube.com/watch?v=LBo_rKN_e-I&t=3s
감사합니다!
728x90
'Study > TIL(Today I Learned)' 카테고리의 다른 글
24.10.17 CS, UE5 (3) | 2024.10.18 |
---|---|
24.10.14 게임 서버 (0) | 2024.10.14 |
24.10.10 게임서버 (4) | 2024.10.10 |
24.10.08 UE5, CS (8) | 2024.10.08 |
24.10.02 UE5, 알고리즘 (1) | 2024.10.02 |