소셜게임 서버 개발 관점에서 본 node.js의 장단점과 대안
DESCRIPTION
play.node node.js conferenceTRANSCRIPT
1st node.js Korea conference
2012.11.20
소셜게임 서버 개발 관점에서 본 node.js 의 장단점과 대안
블루윈드백정상
Page 2
예전엔 PC 온라인 게임 서버 개발자
발표자 소개
Page 3
지금은 모바일 게임 서버 개발자
발표자 소개
Page 4
B-TOWER (iOS / Android)
타겟 프로젝트
Page 5
모든 리퀘스트가 3 초 안에만 처리되면 된다http 베이스전 세계 서비스가 가능해야 함개발 인력 : 1 명 ( 두둥 )시간이 촉박하다 !– 3 개월 안에 출시한다 !
서버 요구사항
Page 6
기존에 많이 쓰던 소셜 플랫폼
Apache / php– 전통의 강자– Zynga 및 많은 게임에서 사용– 익숙하고 편한 언어환경
http://www.raphkoster.com/2010/03/12/gdc10-scaling-social-games-robert-zubek/
Page 7
왜 node.js 를 선택했는가
퍼포먼스자바 스크립트알찬 기본 라이브러리유용한 써드 파티 모듈들
Page 8
왜 node.js 를 선택했는가
퍼포먼스– node.js = libuv (IOCP) + v8 (JIT)– 느릴 수가 없는 조합– 온라인 게임 서버들도 대부분 (IOCP) + (C++) + (lua)
조합– Hello world 로 Apache/php 와 http 성능비교
• Node.js 가 약 10 배정도 빨랐음– 이 정도면 성능은 믿고 가자
• 적절히 타협
Page 9
왜 node.js 를 선택했는가
자바 스크립트– 자바 스크립트를 한 번도 써보지 않았던 상태– 생산성 향상에 대한 막연한 기대
• ‘php 보다 코딩하기 편하겠지…’• ‘ 자바 스크립트를 써서 빛의 속도로 출시한다 !’• 나중에 엄청난 후회…
Page 10
왜 node.js 를 선택했는가
알찬 기본 라이브러리– 소셜 게임 개발에 필요한 것은 다 있음– API 문서도 읽기 쉽게 잘 작성됨
사용한 기본 라이브러리들– http, https– url, querystring– util– buffer, stream– fs– crypto– etc…
Page 11
왜 node.js 를 선택했는가
생산성 향상에 기여한 써드파티 모듈들– node-tds (MSSQL)– node-vows (BDD)– node-xml2js (XML -> json)– ya-csv (CSV)– node-memcache (memcached)– node-twitter (server crash reporter)– node-mysql (MySQL)– node-apns (Apple Push Notification Service)
Page 12
결론
이렇게 된 이상 모든 걸 node.js 로 짠다 !
Page 13
개발 시작
클라이언트 네트웍 라이브러리 : c++– cURL 이용– Xcode / ndk 에서 모두 빌드되어야 했음– 개발하다 보니 windows 에서도 빌드
서버 : node.js– 개발은 windows 7 에서 진행– Windows 2008 Server R2 에서 실행– 왜 ? 게임이 잘 되면 개발자 뽑기 쉬우라고…
• 근데 Windows 에선 안 되는 것이 많다 !• 나중에 많이 후회…
Page 14
에디팅 환경npmjavascriptsingle instance = single threadCPS
난관들
Page 15
에디터
Vim– 늘상 써왔던 그것
findStr– windows 에서 찾은 grep
eclipse– 잠시 썼으나 workspace 관리가 불편해 버림
불편하다 !
Page 16
node.js 디버깅 방법
Google Chrome Developer Tools– 서버를 디버그 모드로 띄우고– eclipse 로 붙어서 확인하는 방법– 안되쟎아
Logging– 늘상 해오던 그것
결론적으로 불편하다 !
Page 17
대안
WebStorm– http://www.jetbrains.com/webstorm/– node.js 를 지원– IDE 에서 구현 후 바로 실행 및 디버깅 가능– 자동 완성 기능– 적절한 가격 ($29 ~ $99)
Page 18
npm
윈도에서는 대부분의 모듈 사용 불가– unix 계열 모듈 의존성 문제가 있음– 대부분의 써드 파티 모듈을 git-hub 에서 직접 다운로드 후
node_modules 폴더에 추가– 어차피 모듈 버전을 프리즈 해야 했으므로 큰 문제는 안 됨
Page 19
자바 스크립트로 비즈니스 로직을 잘 짜기 너무 어렵다
해당 구문이 실행되기 전 까진 문제가 발생하지 않음– 서버가 죽고 나서야 문제를 알게 됨– QA 가 없는 1 인 개발의 슬픈 현실에선 큰 불안요소
javascript
Page 20
너무 암묵적인 게 문제
function Obj() {}
Obj.prototype.value = function() {return 11;
}
function calc(obj) {return obj.value - 1; //should throw an exception!
}
if (require.main == module) {var obj = new Obj();var added = calc(obj) + 1; // NaN + 1 = NaNconsole.log('result: ', added);
}
function
Page 21
var levelTable = {1:10,2:20,3:30
};
levelTable[1] // 10levelTable[4] // undefinedleveltable[4] // ReferenceError
타이포
구문이 실행되는 시점에 죽는 게 함정
Page 22
User.prototype.updateRating = function() {// 플레이어 Rating 업데이트
…};
User.prototype.removeRoom = function(roomId, cb) {this.tower.removeRoom(roomId, function() {
this.updateRating() //exceptioncb();
});
};
this 가 그 this 가 아니군
Page 23
User.prototype.updateRating = function() {// 플레이어 Rating 업데이트
…};
User.prototype.removeRoom = function(roomId, cb) {var self = this;this.tower.getRoom(roomId, function() {
self.updateRating()cb();
});
};
this 가 그 this 가 아니군
Page 24
테스트 주도 개발 ( 강력 추천 )– 클라이언트 사이드 : google test– 서버 사이드 : vows, 자체 개발 tdd 툴– 3 대 크래시 주범이 대부분 테스트 레벨에서 걸러짐– regression 도 방지– 라이브 때 서버가 거의 안 죽어줘서 고마웠음
대안
Page 25
UncaughtException 을 핸들링– 최소한 서버 크래시는 방지– Error 오브젝트가 타입이 애매모호한 게 함정– node-twitter 를 사용하여 uncaught exception 핸들 시
트위터에 알림 ( 강력 추천 )
대안
Page 26
Node.js 는 싱글 스레드 기반– I/O 가 수반되는 작업이나 이벤트는 event loop 에서 작업– 하지만 비즈니스 로직은 하나의 스레드에서 실행– 클로져를 전달한다고 비동기로 처리되는 게 아님– 멀티코어 환경에서 전체 CPU 를 사용하지 못한다는 문제가
있었음
Single instance == single thread
Page 27
cluster– 하나의 인스턴스에서 하나의 포트로 여러 프로세스를
클러스터링• child_process.fork()
– master -> worker 로의 로드 밸런싱 지원
대안
Page 28
var cluster = require('cluster');var http = require('http');var numCPUs = require('os').cpus().length;
if (cluster.isMaster) { // Fork workers. for (var i = 0; i < numCPUs; i++) { cluster.fork(); }
cluster.on('exit', function(worker, code, signal) { console.log('worker ' + worker.process.pid + ' died'); });} else { // Workers can share any TCP connection // In this case its a HTTP server http.createServer(function(req, res) { res.writeHead(200); res.end("hello world\n"); }).listen(8000);}
cluster 예제
Page 29
Continuation-Passing Style– Closure
• 함수 안의 함수• 윗 함수의 레퍼런스를 참조 가능
– Coroutine• 수행 지점을 설정 가능한 서브루틴• yield()등으로 수행을 양보하고 , resume()등으로 양보한 시점부터
실행이 가능• yield, resume 시점에 context 를 주고받을 수 있음
CPS
Page 30
function say11() { var num = 10; var sayAlert = function() { console.log(num); } num++; return sayAlert;}
Closure 예제
Page 31
var coroutine = process.binding(‘coroutine’).coroutine;
var co = coroutine.create(function(name) {var questId = 11;console.log(‘My name is‘, name);console.log(‘Do you want to play this quest?’);var selected = coroutine.yield(questId);if (selected == true) {
console.log(‘Let’s play!’);} else {
console.log(‘See you next time’);}
});
var qId = coroutine.resume(co, ‘hackest’);console.log(‘qId: ‘, qId);coroutine.resume(co, true);
Coroutine 예제
Page 32
한 때 뜨거웠던 토론 주제node.js 는 클로져만 지원퀘스트 짜다보니 코루틴 필요가 절실해짐– 유저 입력 받을때마다 상태 저장하고 if else 떡칠– 클로져로는 짜는게 너무 괴롭다…
근데 코루틴이 없네 ?
Closure, Coroutine
Page 33
node-fiber– node.js 내에 자체 구현한 코루틴과 파이버를 제공– 근데 Windows 에서 실행이 안 된다 !
한참을 찾다가 결국 자체 노드 바인딩을 만들어보기로 결심– js-coroutine 에서 모티브를 얻음– 마침 잉여력도 좀 있었음
찾아본 라이브러리
http://code.google.com/p/js-coroutine/
Page 34
Portable Coroutine Library– 오픈소스– 기본적인 execution control environment 를 제공– C API 제공
붙여볼 코루틴 라이브러리
http://xmailserver.org/libpcl.html
Page 35
node.js 프로그램 구조
native core(V8, libuv, openssl, zlib, etc…)
node bindings(node_socket, node_os, node_zlib,
etc…)
node standard library(socket, os, zlib, etc…)
application code(user implementation)
Page 36
coroutine 추가
native core(V8, libuv, openssl, zlib, libpcl etc…)
node bindings(node_socket, node_os, node_zlib,
node_coroutine, etc…)
node standard library(socket, os, zlib, coroutine, etc…)
application code(user implementation)
Page 37
데모 시연
Page 38
퍼포먼스 때문에 node.js 를 선택– 실제 퍼포먼스 병목은 DB 가 될 가능성이 높음
써드 파티 모듈들로 인해 생산성을 향상javascript 로는 생산성을 향상시키지 못함– node.lua 도 괜찮을 듯
javascript 로 안정적 서비스 하려면 무조건 TDD 를 도입– 언어 특성상 프로젝트가 커지면 핸들 하기 어려워집니다
코루틴이 필요하면 붙이면 됩니다– 애드온 형태로 붙이셔도 됩니다
요약