• Save
인디게임개발자스터디 오픈세미나 1인_개발에_적합한_서버_사이드_솔루션_최재규
Upcoming SlideShare
Loading in...5
×
 

Like this? Share it with your network

Share

인디게임개발자스터디 오픈세미나 1인_개발에_적합한_서버_사이드_솔루션_최재규

on

  • 6,783 views

 

Statistics

Views

Total Views
6,783
Views on SlideShare
6,507
Embed Views
276

Actions

Likes
94
Downloads
0
Comments
5

11 Embeds 276

https://twitter.com 78
http://cafe.naver.com 73
http://www.slideee.com 50
http://blog.netb.kr 29
http://news.imaso.co.kr 28
http://devilchen.tistory.com 6
http://www.joannesoft.com 5
http://www.hanrss.com 3
http://webcache.googleusercontent.com 2
http://www.inoreader.com 1
http://hunking.dothome.co.kr 1
More...

Accessibility

Categories

Upload Details

Uploaded via as Microsoft PowerPoint

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

인디게임개발자스터디 오픈세미나 1인_개발에_적합한_서버_사이드_솔루션_최재규 Presentation Transcript

  • 1. 1인 개발에 적합한 서버 사이드 솔루션 인디게임개발자스터디 ‘오픈세미나’ mail : choijaekyu at gmail 최재규 이 자료는 공개용으로 추가/수정/보강되어 일부분은 강연장에서 보셨던 것과 다를 수 있습니다.
  • 2. 순서 1. 클라우드 시대는 1인 개발을 위한 시대 2. 구글 앱 엔진 3. 포톤 클라우드 4. 아나키 연동
  • 3. 인디인데 왜 서버를 신경써? • 우리의 세상 – 데이터 저장은 디스켓에 – 백업은 자주, 냉장고 자석 병따개는 저 멀리 – 위대한 컨텐츠는 당연히 오랜시간 받아야만 할 수 있는 것 • 93년생의 세상 – 인터넷은 공짜 – 모든 데이터는 내 컴퓨터가 아닌 저 너머에 – 스트리밍이 당연한 세대
  • 4. 인디인데 왜 서버를 신경써? • 우리의 세상 – 포맷을 하면 게임 세이브 파일이 날라가는 것은 당연 • 93년생의 세상 – “앱을 지웠다 깔았는데 왜 내 아이템 다 날 라갔어요? 복구해주세요. 환불해주세요.”
  • 5. 인디인데 왜 서버를 신경써? • 우리의 세상 – 게임은 당연히 혼자하는 것 – 같이 할 수 있으면 더 좋은 것 • 93년생의 세상 – “이 세상에 혼자하는 게임이 어딨어요?” – 메이플스토리가 인생 첫 게임
  • 6. 소셜(Social) 시대 • 모든 이들이 컴퓨터를 한 대씩 손에 들고 다니 는 세상 • 저장된 폰 번호로 그들간의 관계를 알 수 있다 • 게임에서 그 관계를 이용함으로써 바이럴 마케 팅이 가능한 세상, 이제 필수인 세상
  • 7. 소셜(Social) 시대 • 바이럴 마케팅이 주요 마케팅 채널인 인디에게 소셜 요소의 활용은 매우 중 요하다 • 게임 디자인부터 소셜 요소를 고려한다
  • 8. 아무튼, 서버가 필요해 • 서버 하드웨어 구매 • IDC 계약, 방문 설치 • 우여곡절 끝에 운영체제 설치시작 • 터미널 접근이 안돼 IDC 업체 컨설팅 • 아파치, PHP, MySQL 설치
  • 9. 아무튼, 서버가 필요해 • 접속이 안되, 지웠다 다시 깔아보고 • 알고봤더니 방화벽 설정을 엉망으로 • 이제서야 코딩 시작 • 대충 돌아가기는 함 • 퍼포먼스 안 나옴, 각종 매뉴얼 들쳐 봐야함
  • 10. 아무튼, 서버가 필요해 • 사람들이 몰려들기 시작, 모니터링 그래프가 하늘을 찌르기 시작 • 하드웨어 늘려야 하나 고민, 근데 배 달만 3일 이상 걸려 • 갑자기 서버 오류가 왕창 생겨 • 알고 봤더니 MySQL 디스크 꽉 참
  • 11. 아무튼, 서버가 필요해 • 주문한 하드웨어 이제 도착 • 언제 설치? 이미 사람들 다 빠져나감 • 망했다-_-; • 남은건 하드웨어뿐. • 중고로 다시 팔아? 애물단지 • IDC 계약기간 안 끝났잖아-_-;
  • 12. 아무튼, 서버가 필요해 • 해외에 진출하게 되면? 마이 팬 일만양병설 • 혹여 대박이 나서 사용자가 끊임없이 들어오면? 배달만 3일이라고!!! • 내가 자는 중에 에러나면?
  • 13. SE의 필요성 • System Engineer • 시스템 관리 자체만으로도 충분히 한 사람 이상의 비용이 들어감 • 인디에게는 치명적!
  • 14. 클라우드 시대는 1인 개발을 위한 시대
  • 15. 클라우드 시대 “제프님이 이르시되 클라우드가 있게 하여 라 하시니 제프님이 보시기에 참 좋았더라” 제프 베조스
  • 16. 클라우드 시대 • IaaS (Infrastructure as a Service) – 하드웨어만 제공 • PaaS (Platform as a Service) – OS, 웹서버, DB, 언어 Runtime까지 제공 • Saas (Software as a Service) – 회원가입 관리, 데이터 저장, 노티 같은 일 반적인 로직까지 제공
  • 17. 출처 http://www.cbc.radio-canada.ca/en/reporting-to-canadians/sync/sync-issue-1-2012/cloud-services/ IaaS PaaS SaaS기존
  • 18. 클라우드 시대 • IaaS – Amazon (AWS) – Google Compute Engine – Digital Ocean • PaaS – Google App Engine – Heroku • SaaS – Parse – BaaS.io
  • 19. 구글 앱 엔진 Google App Engine
  • 20. 구글 앱 엔진 (GAE) • PaaS – OS, 웹서버, DB, 언어 Runtime까지 제공 • 즉, 우리는 게임 서버로직 코드와 데이 터만 올리면 나머지 구글느님께서 알아 서 다 해줌
  • 21. 어디까지 알아서 해주는데? • 디스크/네트워크 용량 제한 없음 – 사용한 만큼 돈을 냄 • 서비스 장애 없음 (가용성 99.999%) – 공짜 • 사용자가 늘어나면 알아서 확장 – 돈을 미리 넣어두면
  • 22. 지원하는 언어 1. Python 2. Java 3. Go 4. PHP
  • 23. 파이썬 • 구글에서 자바 다음으로 많이 쓰이는 언어 • 코드 들여쓰기가 문법적으로 고정 (다른 언 어 사용자의 거부감, 코드 스타일의 통일화) • 막강한 프레임워크와 라이브러리 즐비 • Python 2.X와 3.X는 호환 안됨 • 공통의 코드로 Windows / Linux / Mac에 서 돌아가는 커맨드라인 툴을 만드는데 파 이썬만한게 없었다 귀도 반 로썸
  • 24. Web Server Browser Web Server http://www.site.com/a/b/index.html index.html 파일 내용 • 종래의 웹 서버는 파일 경로를 요청하면 그 파일을 전송해주는 역할 위주였지만 (혹은 그 파일을 스크립트를 통해 실시간으로 변형해 서 제공하는)
  • 25. RESTful Service http://www.site.com/users/choijaekyu 유저 choijaekyu의 정보 XML, JSON, YAML Browser Web Server • 현재 웹서버는 특정 자원을 의미하는 URI로 정보를 요청하고 그 에 따른 정보를 특정한 포맷(XML, JSON, YAML)으로 응답하는 서버의 역할을 한다.
  • 26. HTTP • 게임 개발자는 HTTP에 대한 재인식이 필요 • 이제 웹 브라우저와 웹 서버가 통신하는데 만 쓰는 프로토콜이 아님 • 어떤 플랫폼이든 어떤 네트워크 환경이든 서버와 통신이 가능한 유일한 프로토콜 (포트 80번은 왠만하면 다 열려 있으니)
  • 27. REST API Design https://api.twitter.com/1.1/statuses/mentions_timeline.json?count=2&since_id=14927799 https://dev.twitter.com/docs/api/1.1/get/statuses/mentions_timeline API 주소 버전 API 종류 API 이름 리턴타입 파라미터 • REST API의 디자인이 중요해짐
  • 28. Postman • 특정 REST API를 만들 때 마 다 HTML페이지를 만들 수 없으므로 적합한 툴을 활용 • REST Client • 크롬 앱 • 구글에서 postman 검색
  • 29. DataStore • NoSQL 스타일의 데이터 저장소 • Google 내부에서도 사용하는 솔루션(Google Apps) • Schemaless • 트랙잭션 지원 (하지만 완벽하지 않다) • 한 달에 2조 개의 요청을 처리한다고…ㅎㄷㄷ • 설마 구글인데 NoSQL이라고 데이터 유실을 당연시 여기지 않겠지…않을꺼야..
  • 30. Entity Kind : Note ID : 123456789 Key Property
  • 31. Entity Kind : BBS ID : 111 Key Kind : Article ID : 333 Key Kind : Article ID : 444 Key Kind : Article ID : 555 Key • 자유롭게 부모자식 관계를 지정할 수 있음
  • 32. Entity Kind : Notes ID : 111 Key Kind : Note ID : 555 Keynote_key = ndb.Key(‘Notes’, 111, ‘Note’, 555) • 부모자식 관계가 깊어질수록 Key의 길이가 길어짐
  • 33. Google Cloud SQL • 그냥 MySQL이다 • DataStore로 로그 데이터 / 싱글 게임 데이터를 처 리하고 • Cloud SQL로 캐쉬 아이템 / 게임머니 획득, 소비 트랜잭션을 처리하면 좋지 않을까
  • 34. Stateless • 서버 입장에서 아까 들어온 요청과 지금 들어온 요청이 같은 클라이언트인지 알 수 있는 방법이 없다. • 더군다나 같은 유저가 폰과 타블렛을 번갈아 들어온다면? • Stateless를 전제한 게임로직 설계가 중요해졌다
  • 35. 인증 - 쿠키와 세션 Browser Web Server 인증이 필요한 작업을 요청 로그인 페이지로 응답 ID / PW 전송 세션아이디를 쿠키에 등록 매 요청마다 세션아이디를 헤더에 넣어줌 SID ----------- - 파일 - 메모리
  • 36. GAE - User API • Google Account를 바로 연동 • 사용자 닉네임, 메일 주소, 유니크 아이디를 알 수 있음 (구글 내부 에서도 사용하는 것) • 닉네임과 메일 주소는 변경 가능하지만 유니크 아이디는 절대불변 • 자체 계정 인증은 따로 구현해야 (webapp2_extra.session를 활용 하면 간편해질듯)
  • 37. GAE Service • Memcache – 캐쉬 가능!! • Task Queue – 다른 임의의 시스템과 유연하게 통신할 수 있는 채널 • Translate API – 서버에서 채팅 문장을 해당 국가 언어로 번역해서 제공해줄 수 있다 • Search API – 구글의 검색 엔진을 기능을 그대로 사용 • Google Cloud EndPoints – 각 플랫폼의 REST API를 손쉽게 생성시켜줌
  • 38. Google Cloud Platform • Google Cloud Storage – 사용자가 올리는 이미지, 동영상 저장 • Google Compute Engine – Amazon의 AWS와 같은 IaaS – 임의의 시스템을 마음껏 구성 – Task Queue 서비스로 GAE와 통신
  • 39. GAE는 실시간 위치 동기화 로직을 처리하기 어렵다 • FPS, 레이싱 같은 실시간으로 위치 정보를 주고 받아야 하는 경우 • 태생적 문제 – GAE만 그런게 아님 – HTTP가 Stateless 프로토콜이기 때문에 어쩔 수 없는 한계 • 팜류의 비동기 로직은 괜찮음 – 이런 종류의 요구사항에 적합한 Channel API도 있음
  • 40. 포톤 클라우드 Photon Cloud
  • 41. ExitGames • 독일, 2003~ • 게임 서버 엔진 전문회사 – Photon Server – Photon Cloud • 레퍼런스 게임이 좀 약한듯
  • 42. Photon Server • Windows 기반 • 코어는 C++ (IOCP) • 비즈니스 로직은 C#
  • 43. Photon Server • 시작은 공짜 • 별다른 인증없이 회원 가입후 다운로드 가능 • Per App/Server Instance 가격정책은 쫌…
  • 44. Photon Server • 대부분의 클라이언트 플랫폼 지원 • Android NDK 지원은 아나키한테 필수였음 • 서버가 WebSocket을 지원하고 HTML5(JavaScript) 클라이언트 SDK도 존재
  • 45. Photon Server • 미리 구현된 비즈니스 로직 소스 제공 – Lite – LiteLobby – MMO – LoadBalancing
  • 46. Photon Cloud • SaaS • LoadBalancing 소스를 이용 • 일반적인 룸 방식의 게임로비 기본 로직 이 구현되어 있음 • 알아서 분산처리 • 문서가 너무너무 부실함
  • 47. Photon Cloud • 현재 한국 서버 접속 안됨 • 미국 동부<->서부 200ms • 일단 일본 서버 쓰는 데 괜찮음
  • 48. Photon Cloud • 동접으로만 제한 • 한 달 500명 동접 이면 대략 4만원 • CCU Burst
  • 49. 방 • 공개방 / 준-비공개방 (Visible) • 방 생성 (Create) • 방 조인 (Join) • 방제 지정 입장 (JoinRoom) • 랜덤 입장 (JoinRandomRoom) • 최대 플레이어 수 제한 (Max Players) • 방 상태 : Opened or Closed • 그 방에서만 유효한 고유 Player ID 발급해줌
  • 50. 방장(Host) • 서버 로직은 작성할 수 없다. • 방장 역할 로직은 직접 구현해야함 – 1. 방 생성 – 2. 인원 확인 (모두 알 수 있지만 그래도 플레이어가 들어오고 나오는 것은 방장을 통해서) – 3. Ready 확인 후 방 Closed – 4. 로딩시작 알려줌 – 5. 로딩이 다 끝난 것을 확인 – 6. 게임 시작 카운트 • 플레이 도중에 방장이 튕겼을 때 방장 역할 이전은 알아서 구현해야함-_-;; • 서버 로직을 추가할 수 없으니 이것이 Cloud의 약점
  • 51. Photon Cloud 사용시 주의점 • opRaiseEvent 함수를 호출해도 바로 보내지 않는다 • 하나의 Room에서 처리할 수 있는 초당 최대 메시지 숫자가 정해 져 있기 때문에 한 프레임에서 요청한 send들은 한꺼번에 보낼려 고 하는듯 • 이 현상에 의한 전송 지연을 서버가 멀어서 그런거라고 오해할 수 있다 g_client->opRaiseEvent(…); g_client->Service(false); // 이때 send 호출
  • 52. Photon Cloud 사용시 주의점 • 방이 생성 된 후에 플레이어가 모두 튕겨도 방이 한동안 없 어지지 않는다. • 그래서 반드시 게임 시작 전에 방의 visible, open 값을 false시킨다.
  • 53. Photon Cloud 인증 • Facebook, steam 지원 • 자체 계정은 REST API 서버를 준비해야함
  • 54. 포톤 클라우드와 아나키 연동
  • 55. Photon Cloud 세팅 • https://cloud.exitgames.com 1. 계정 생성 2. New App 등록 3. App ID 확인 4. Client SDK 다운로드 – 주의: Photon Server SDK와 Photon Cloud SDK가 구별 되어있음 – NDK, Windows용 SDK를 각각 다운 받음
  • 56. Photon Cloud 세팅
  • 57. Anarchy Lib 세팅 • SDK 안에 들어있는 라이브러리 파일들을 적절히 아나키 폴 더에 카피 • Android NDK용 SDK에 들어있는 .a 파일들은 아래에 – Release 라이브러리: C:HavokAnarchySDKLiband_vs2010_anarchyrelease – Debug 라이브러리: C:HavokAnarchySDKLiband_vs2010_anarchydebug • Win32용 SDK에 들어있는 .lib 파일들은 아래에 – Release 라이브러리: C:HavokAnarchySDKLibwin32_vs2010_anarchydebug_dll – Debug 라이브러리: C:HavokAnarchySDKLibwin32_vs2010_anarchyrelease_dll • 헤더는 그냥 공통으로 씀 (같은 C++ 코드이라서)
  • 58. Anarchy Lib 세팅 • Visual Studio에서 Android, Win32 각각 Debug, Release 각각 라이브러리 추가 • 헤더 경로도 추가
  • 59. 코딩 #include "LoadBalancing-cpp/inc/LoadBalancingClient.h" class MyListener : public ExitGames::LoadBalancing::Listener { // 리스너 상속 받아서 구현 }; MyListener g_listener;
  • 60. 코딩 ExitGames::LoadBalancing::Client* g_client = NULL; g_client = new ExitGames::LoadBalancing::Client(g_listener, "APP ID as string", "0.1", // version "user_name"); g_client->connect("app-jp.exitgamescloud.com"); // MyListener::connectReturn 콜백 아까 대쉬보드에 서 확인한 App ID를 넣어준다
  • 61. 코딩 // 매 프레임 마다 아래 함수가 호출되도록 설치 // 이 함수가 서버로부터 받은 패킷을 dispatch한다. g_client->service();
  • 62. 요청 / 응답 Client Server Client::opCreateRoom Listener::createRoomReturn Client::opJoinRoom Listener::joinRoomReturn
  • 63. 요청 / 응답 Client Server Client::opJoinRandomRoom Listener::joinRandomRoomReturn Client::opLeaveRoom Listener::leaveRoomReturn
  • 64. 게임 패킷 • 게임패킷 : 아이템 먹고 총쏘고 점프하고 하는 것들을 주고 받는 패킷 • Photon Cloud에선 CustomEvent라 명칭 • Client::opRaiseEvent 으로 보내고 • Listener::customEventAction 으로 받음 • 이벤트를 구별하는 eventCode 값은 사이즈가 Byte라서 패킷 종류는 총 256개만 가능 • 보내는 대상은 입장시 부여받은 Player ID를 통해서 전체 또는 일부한테만 보낼 수 있음 • Common::HashTable를 이용해서 데이터를 교환
  • 65. 요청 / 응답 Client Server Client::opRaiseEvent Client Listener::customEventAction Client Listener::customEventAction Client Listener::customEventAction
  • 66. Common::HashTable • 게임 패킷의 내용을 Key / Value 형태로 HashTable에 채워넣어 야함 • Byte Array를 바로 보내는 기능은 없다. • 게임 로직에 Photon Cloud 코드를 깊게 연관시키긴 싫다. 바이 트 배열의 전달만 잘해달라고!! • 무엇보다 값을 넣고 빼는 코드가 아름답지 않아요 (C#은 아름답 게 됨-_-;)
  • 67. Common::HashTable • 다행히 Value로 Byte Array를 넣을 수 있는 기능이 있다 • char packet[1024]; // 게임패킷 내용을 여기에 Serialize시켰다 치고! • short packet_size = 1024; // 그 크기가 1024바이트라 치고! • // Client::opRaiseEvent 호출하기 전에 값을 넣는다. • ExitGames::Common::Hashtable param; • param.put(“game_packet", (nByte*) packet, packet_size); • g_client->opRaiseEvent(true, param, packet_id); • // Listener::customEventAction에서 • ExitGames::Common::ValueObject<nByte*> obj(receivedEventContent.getValue("game_packet")); • nByte* packet = *( obj.getDataAddress() ); // zero-copy • short packet_size = *( obj.getSizes() );
  • 68. 그럼 • Serialize / Deserialize를 어떻게 할 것인가… • 방법 – 패킷 구조체를 작성하고 수동으로 대입 – 유틸리티 코드를 작성 – 외부 라이브러리 활용 (Google Protocol Buffer)
  • 69. Google Protocol Buffer • 구글에서 사용하는 공식 라이브러리 • 구글 내부에서 4만8천여개 메시지 정의 • RPC 아님 (Stub코드는 만들어주지만) • 자체 언어로 메시지(구조체)를 정의 • C++ / Java / Python 코드 생성
  • 70. GPB 특징 • 메시지 Identification을 정의하지 않음 • 즉 이 byte array가 어떤 메시지 구조를 가지고 있는지 스 스로 판별할 수 있는 수단을 마련해야 함 • 메시지 사이즈 정보 또한 정의하지 않음 • 즉, 패킷을 구성할 때 ID와 SIZE를 헤더로써 맨 앞에 두고 이어서 Serialize된 데이터를 붙여줘서 하나의 패킷으로 완 성시킴
  • 71. GPB 활용 • 네트워크 패킷 정의 • 파일 포맷 • DB Blob컬럼 포맷 • 등등… 무궁무진 • Reflection 기능도 지원해서 JSON 텍스트로 뽑는 것도 쉽 게 추가 가능
  • 72. GPB 메시지 생성 • C 구조체 정의 스타일이라 크게 어렵지 않음 // GameProtocol.proto package Protocol; message C2A_PlayerDamaged { required int32 client_id = 1; required int32 missile_owner_id = 2; required float pos_x = 3; required float pos_y = 4; required float pos_z = 5; required float angle = 6; };
  • 73. GPB 메시지 생성 • C 구조체 정의 스타일이라 크게 어렵지 않음 enum EItemType { EItemType_Unknown = 0; EItemType_Gear = 1; EItemType_Missile2 = 2; EItemType_Missile3 = 3; EItemType_Missile4 = 4; EItemType_Reflection1 = 5; EItemType_Reflection2 = 6; EItemType_Reflection3 = 7; EItemType_Reflection4 = 8; EItemType_Random = 9; EITemType_ItemBox = 10; };
  • 74. GPB 메시지 생성 • protoc.exe --cpp_out=. GameProtocol.proto • GameProtocol.pb.h, • GameProtocol.pb.cc 파일이 생성됨 • 저는 protoc의 소스를 약간 수정해서 메시지별로 고유 숫 자 값을 생성시키도록 했습니다. – 패킷 아이디로 활용
  • 75. GPB 메시지 사용 • set_변수이름() 함수로 값 세팅 Protocol::C2A_PlayerDamaged pkt; pkt.set_client_id(m_client_id); pkt.set_missile_owner_id(param->missile_owner_id); pkt.set_pos_x(pos.x); pkt.set_pos_y(pos.y); pkt.set_pos_z(pos.z); pkt.set_angle(rot.x); NetSendToAll(pkt); // 이 함수에서 pkt의 내용을 시리얼라이즈(GPB의 함수호출)하고 // Common::HashTable 객체를 하나 만들어서 시리얼라이즈된 byte array를 넣고 // 패킷 아이디와 사이즈도 HashTable에 넣어준다. (받는쪽에서 패킷 종류와 크기를 알아야하니 까) // opRaiseEvent 함수를 호출하고 Service(false)함수를 호출한다.
  • 76. GPB 메시지 사용 • 변수이름() 함수로 값을 가져옴 Protocol::C2A_PlayerDamaged pkt; if ( pkt.ParseFromArray( packet, packet_size ) ) { int owner_id = pkt.missile_owner_id(); float pos_x = pkt.pos_x(); float pos_y = pkt.pos_y(); float pos_z = pkt.pos_z(); float angle = pkt.angle(); }
  • 77. 1인 개발의 서버개발 전략 • 일반적인 게임로직은 GAE 활용 – 유저데이터 저장/불러오기 – 지인들과 랭킹 정보 공유 – 유저 로그 수집, 통계처리 • 실시간 대전류 로직은 Photon Cloud 활용 – GAE에서 게임 한판을 의미하는 토큰을 발행하고 Photon Cloud는 그것을 통해 인증
  • 78. 1인 개발의 서버개발 전략 • 두 서비스 모두 사용자가 적으면 공짜! • 사용자가 늘어나도 저렴함 • 더 늘어나면? 그건 대박이므로 그 때가서 고민해도…
  • 79. 감사합니다