Advertisement

임태현, 게임 서버 디자인 가이드, NDC2013

devCAT Studio, NEXON
Apr. 25, 2013
Advertisement

More Related Content

Slideshows for you(20)

Advertisement

More from devCAT Studio, NEXON(20)

Recently uploaded(20)

Advertisement

임태현, 게임 서버 디자인 가이드, NDC2013

  1. 게임 서버 디자인 가이드 넥슨 W엔지니어링팀 임태현
  2. 게임 서버 디자인 가이드 너무 심하게 허세 부린 것 같아서 패턴에서 가이드로 색도 살짝 흐리게 ..ㅋ
  3. 자기소개 2002년 카이스트 전산과 졸업 2002년 넥슨 입사 2002년 마비노기 2007년 허스키 익스프레스 2010년 마비노기2
  4. 12년
  5. 한화는 언제 이길까.. 작업 공정 개선 동료들과의 소통 삼순이가 자꾸 종이 먹어 기술 발전 할 줄 아는 게 없어 매너리즘 내 작업 자랑질
  6. 우리 서로 얘기해봐요~ 저는 당신이 어떻게 서버를 만들고, 어떻게 이런 생각을 하였는지 궁금합니다. 그래서 제가 먼저 시작해보겠습니다.
  7. 목차 • 시작하기 • 기초 설계하기 • 설계 확장하기 • 마무리
  8. 시작하기
  9. 왜, 게임 서버를 직접 만들수 밖에 없는가?
  10. 소규모 게임에는 일부 적용 Flash Media Server Java 기반 웹 게임 서버 Etc …
  11. MMO-Game 용으로도 일부 시도 실패하였음 느리고 쓰기 불편
  12. WHY? 왜 실패하였을까?
  13. MMO 게임의 특징 MASSIVELY = 매우 많은 MULTIPLAYER = 사람이 ONLINE = 함께 GAMES = 게임을 한다
  14. MMO 게임의 특징 MASSIVELY = 매우 많은 MULTIPLAYER = 사람이 ONLINE = 함께 GAMES = 게임을 한다 대부분은 여기가 문제
  15. Massive 문제의 해법들 • 멀티스레드 • 백엔드 분산 • 서버 샤딩 • 플레이어 제한 • Etc …
  16. 플레이어 플레이어 플레이어
  17. 플레이어 플레이어 플레이어 NPC NPC NPC NPC NPC NPC
  18. ….
  19. 이 게임들을 같은 방식으로 구현할 수는 있다 하지만 성능에 문제가 생기거나, 구현방법이 매우 어려워질 것이라는 것은 쉽게 상상 할 수 있다.
  20. 정리 • 게임 서버의 핵심 구조는 게임 디자인(기 획) 에 매우 민감하게 반응한다. • 역으로 서버의 구조로 인해 디자인에 제한 이 생긴다. • 서버 프레임워크 전체를 가져와 쓰는 것은 게임의 유니크함을 해칠 수 있다.
  21. 게임은 유니크함을 가지고 있다 그리고, 플레이의 유니크함이 코드를 유니크하게 만든다 그러니 직접 만들 수 밖에 없다…
  22. 기초 설계
  23. Logic(로직) Starter Kit Input(입력) Execute(실행) Network Event System Scheduler Event Callback Thread Model Server Distribution Backend Query Login/out Game Play Resource Management
  24. 스레드 모델 확장 • Single Thread • Input Thread • Custom Thread Pool • Object Bound Thread
  25. Single Thread • 입력을 폴링으로 처리한다. • 모든 로직이 순차적으로 처리된다.
  26. Network MainLoop PacketHandler_Login PacketHandler_Attack Players Objects System Scheduler PacketTranslator Input Execute Logic Listen() Update() Close() Invoke() Update() packets += network.Update(); packets += scheduler.Update(); translator.Execute(packets); Add() Remove() Get() Add() Remove() Get()
  27. 싱글 스레드 모델 특징 • 구조가 간단하다. • Lock 문제가 발생하지 않는다. • 멀티코어의 이점을 사용할 수 없다. • 스레드 잠김이 없는 경우 꽤 빠르다.
  28. Input Thread • 입력이 비동기 IO 일 때 사용 가능하다. • 로직이 IO 스레드에서 실행된다. • 별도의 스레드를 생성하지 않는다.
  29. Network Executer PacketHandler_Login PacketHandler_Attack Objects System Scheduler PacketTranslator Input Execute Logic OnConnect() OnReceive() OnExpire() void OnHandle(Packet packet) { var handler = transaltor.Translate(packet); Call(handler); } Add() Remove() Get() Translator() Resource Lock
  30. 인풋 스레드 모델 특징 • Lock 문제가 발생한다. • 스레드를 관리하지 않는다. • 스레드가 잠기는 경우에 성능 손해가 비교적 적 다.
  31. Custom Thread Pool • 로직이 스레드 풀에서 실행된다. • 실행 모듈에 작업 큐가 있다.
  32. Network Executer GameThread TaskHandler Objects System Scheduler ThreadPool Input Execute Logic OnConnect() OnReceive() OnExpire() void OnHandle(Packet packet) { var task = packet.ToTask(); TaskQueue.Enqueue(task); ThreadPool.SetSingal(); } Add() Remove() Get() SetSignal() Resource Lock TaskQueue Enqueue() Dequeue() void OnSingal() { task = TaskQueue.Dequeue(); Run(task); }
  33. 커스텀 스레드 풀 모델 특징 • 스레드 수를 조절해, 성능을 최적화 할 수 있다. • 입력순서와 처리 순서가 달라 질 수 있다. • Lock 문제가 발생한다. • 스레드가 잠기는 경우에는 성능 손해가 크다. – 데이터베이스나 외부 서비스 동기화 쿼리에 의한 성능 손해가 매우 크다
  34. 커스텀 스레드 풀 모델 특징 • 스레드 수를 조절해, 성능을 최적화 할 수 있다. • 입력순서와 처리 순서가 달라 질 수 있다. • Lock 문제가 발생한다. • 스레드가 잠기는 경우에는 성능 손해가 크다. – 데이터베이스나 외부 서비스 동기화 쿼리에 의한 성능 손해가 매우 크다게임에서는 치명적인 문제가 될 수 있다
  35. Object bound Thread • 앞의 모델에서 입력 순서 문제를 해결 • 스레드 별로 리소스 관리자가 할당된다
  36. Executer GameThread TaskHandler ThreadObjects Execute Logic void OnHandle(Packet packet) { var task = packet.ToTask(); var target = task.GetTarget(); TaskQueue.Enqueue(target , task); } Add() Remove() Get() void OnSingal() { task = MyQueue.Dequeue(); Run(task); } ThreadPool void Enqueue(target, task) { thread = FindThreadByObject(target); thread.Enqueue(task); thread.Signal(); } Per Thread
  37. 오브젝트 기반 스레드 모델 특징 • 특정 객체를 타겟으로 하는 입력간의 순서가 보 장된다. • Lock 문제가 거의 발생하지 않는다. • 전체 객체 검색이 불가능하다 • 객체가 많이 몰리게 되는 곳이 있다면 성능 손해 가 매우 크다.
  38. [복습] Single Thread Input Execute Logic
  39. [복습] Input Thread Input Execute Logic
  40. [복습] Custom Thread Pool Input Execute Logic
  41. [복습] Object Bound Thread Input Execute Logic
  42. 정리 • 여러 모델의 장단점이 존재한다. • 베이스 프레임워크를 중간에 변경하는 것 은 매우 어렵다. • 초기단계에서 게임의 최소한의 사양을 정 하는 것이 좋다. – 불가능하다면 구현이 제일 간단한 싱글 스레드 모델로 만든다.
  43. 설계 확장하기
  44. Interaction
  45. 플레이어 월드 MMO 의 경우 인터랙션이 지리적인 관계로 이루어지는 경우가 많다
  46. 플레이어 월드 MMO 의 경우 인터랙션이 지리적인 관계로 이루어지는 경우가 많다 인터랙션 레벨이 높음 인터랙션 레벨이 낮음
  47. Game World 게임상의 지리적인 상태를 표현하고 객체의 배치와 이동이 가능
  48. 지형 데이터 객체 관측자 아웃풋 게임 로직 객체와 관측자가 구분되지 않는 경우도 있음 Starter Kit
  49. 플레이어 캐릭터 지형 데이터 플레이어 시야 몬스터 네트워크 시야에 들어오는 정보를 네트워크로 전달
  50. 기본적인 동작 CreateObject 객체가 생성되었다 객체가 시야안에 들어왔다 DestroyObject 객체가 파괴되었다 객체가 시야밖으로 나갔다 Broadcast 객체가 액션/이동을 하였다 객체의 상태/외형이 변하였다 시야범위
  51. 기본적인 동작 FindInRange 거리안에 있는 객체 검색 GetDistanceWith 다른 객체와의 거리 참조
  52. 시야범위 안에 있는 객체들의 목록 검색 시야범위에 따른 객체들의 입장/퇴장 이벤트 일반적으로 공간 분할을 이용해서 검색속도를 향상
  53. 다양한 공간 분할 방법 • 동적분할 – 쿼드 트리 – 서클 트리 • 정적 분할 – 타일
  54. 타일 분할 간단 소개 • 구현이 간단하다 • 초기화 비용이 거의 없다 (via 동적분할) • 시야 거리를 동적으로 바꾸기 어렵다 • 객체의 밀도가 낮아도 속도향상은 적다
  55. 7 119 10 85 6 1 2 3 13 14 15 16 12 4 보이는영역 보이지 않는 영역 나 서로의 행동을 지켜본다 8번으로 이동시 시야에서 사라진다 10번으로 이동시 시야에 나타난다
  56. 서버가 보는 심리스 월드 • 클라이언트 기법은 이미 많은 곳에서 소개 • 서버상에서 심리스 월드 구현에 대한 이야기
  57. 심리스 월드를 바라보는 관점 레벨 디자인 : 세계가 단절 없이 이어져 있다. 클라이언트 : 리소스 절차적 로딩을 한다. 서버 : 같은 공간분할 데이터로 관리된다.
  58. 눈에 보이는 객체는 같은 서버에 배치하는 것이 좋다 서버에서의 인터랙션 : 객체의 값 읽기/변경 같은 메모리 공간상에 없으면 처리가 매우 복잡하다 외형, 이동 및 액션 공격/피격, 강제 상태 변경
  59. 심리스 월드의 서버 제약 눈에 보이는 객체들은 같은 서버에 배치하는 것이 좋다. 메모리, 동시 접속자의 제한 플레이어 100 vs NPC 1000+
  60. 거대한 심리스 월드 해결방법 • 조각내기 – 걸어서 이동 할 수 없는 곳은 모두 분리하다. – 배타고 대륙이동, 전송게이트로 이동, 등등.. • 서버 분산 – 프록시 객체를 이용해서 여러 서버에 분산가능 – 안정화 시키기 매우 어렵다. • 메모리, CPU 를 늘린다. – 공간분할후 부분적으로 독점을 해서 멀티스레드로 확장 – 이게 짱인듯…
  61. 정리 • 지리적인 기준으로 인터랙션을 할 경우 게임 월드의 개념이 필요하다. • 월드의 크기가 커지면 공간 분할을 한다. • 심리스를 할 수 있는 것과 해야만 하는 것 을 구분한다.
  62. 동기화 vs 비동기
  63. 서비스의 속도를 떨어트리는 주된 이유 공회전
  64. 공회전의 주요 원인 • DB 요청 • 객체 잠금-Lock • 명시적 대기 – Sleep(); – Event.Wait();
  65. 해결 법 비동기 처리
  66. 샘플 : 우편 처리 String ReadLetter(id) { letter = db.QueryLetter(id); return letter.Text; } DB 여기까지 잠김상태
  67. 샘플 : 우편 처리 - 비동기 void ReadLetterBegin(id) { db.BeginQueryLetter(id); } string ReadLetterEnd(id) { return db.BeginQueryEnd(id); } DB
  68. 그럼 비동기로 만들면 되는 거 아닌가?
  69. 비동기 코드 실제 상황 Begin DB #1 … … End DB #2 DB #3 … DB #1
  70. 선택의 시간 • 동기화 코드 – 코드 작성에 유리하다 – 성능에 불리하다 • 비동기 코드 – 성능에 유리하다 – 코드 작성에 불리하다
  71. 모델을 적당히 조정해서 최적의 경우를 찾아 낸다. (너무 뻔한 얘기지만) 경험이 필요하지만, 주위에 도움을 얻을 방 법은 많다.
  72. 동기화 코드 모델 샘플 제안
  73. Input Thread • 입력이 비동기 IO 일 때 사용 가능하다. • 로직이 IO 스레드에서 실행된다. • 별도의 스레드를 생성하지 않는다. 이것을 기반으로 구성해본다
  74. N E T W O R K OnReceive LOGIC 잠금상태 Player 플레이어게 랙으로 느껴진다
  75. OnReceivePlayer난 빠르지~ 어!!! 반응이 좀 느린데 T W O R K
  76. • 잠금을 썼을 때 성능저하가 입력소스로 제 한된다 • 보통은 플레이어 한 명에게 해당된다 • 최대 잠금 시간을 조절해서 (1s 이하) 불쾌 감이 적게 할 수 있다.
  77. 비동기화 코드 모델 제안 …은 없다 • 개인적으로 싫어한다. • 필요하면 (울면서) 만들긴 한다.
  78. 정리 • 동기화 로직은 코드를 깔끔하게 한다 • 비동기 로직은 성능향상을 시킨다 • 이 둘 사이에서 균형을 잡아야 한다. – 개인적으로는 코드가 단순해 지는 쪽을 선호한다.
  79. 마무리
  80. 이야기 하고 싶은 것 복습 저는 당신이 어떻게 서버를 만들고, 어떻게 이런 생각을 하였는지 궁금합니다. 그래서 제가 먼저 시작해보겠습니다.
  81. 서버 개발을 이제 막 시작하는 분에게는 막 막한 상황에서 가이드가 되기를 바랍니다. 서버 개발에 익숙하신 분들에게는 더 좋은 아이디어의 피드백을 함으로써 서로의 발전 에 도움이 되기를 기대해 봅니다.
  82. 못 다한 이야기들
  83. 데이터 베이스 로직 변경점 저장과 데이터베이스 성능 문제 서버 샤딩과 관리 샤드 vs 원 월드 vs 원 월드 채널링 로깅과 오류 억제 장치 오류 발생 통보와 안정성 향상을 위한 장치들
  84. 감사합니다
Advertisement