2012-04-21

Node.js로 25만 동접 만들기

via caustik's blog

node.js 를 10만 동접으로 스케일링하기

  • 10만 동접을 처리하는데 CPU 점유율 40%, (virtual) 메모리 1.4G 를 차지함. 이 정도면 rackspace 2G 클라우드 서버일 경우 시간당 0.1$ 로 가능함.
  • 각 연결은 5초에 한번 메시지를 보냄. 대략 초당 4만개의 JSON 패킷이 보내짐. 응답성도 좋음.

이런 성능을 위한 설정은:

  • Nagle 알고리즘을 사용안함: 빠른 응답성을 위해 커널 내부에 네트워크 버퍼링을 사용하지 않고 즉시 보내지도록 함. socket.setNoDelay().
  • v8의 idle 가비지 컬렉션을 끄기 위해 --nouse-idle-notification 옵션 사용: JS 객체가 2백만개 정도 되면 몇 초마다 가비지 컬렉션 때문에 1초 가까이 랙이 걸림. 실제로 객체들을 순회하는 데만 이 정도의 시간이 소모됨.
    [역주] 소스 코드를 보면 --expose_gc 옵션으로 실행해서 gc()를 실행할 수 있게 한 다음, /debug/gc 메시지를 보내서 가비지 컬렉션을 하게 되는데, 이걸 실행하는 순간 랙은 뭘 해도 피할 수 없음. ㅠㅠ

node.js 로 25만 동접 만들기

  1. 가장 최근 태그된 v8 리비전의 성능이 그나마 낫다.

  2. 25만 연결은 v8의 1.4기가 힙 메모리 제한 하에서의 최대치. 이 상황에서도 CPU 사용량이나 메모리 사용량이 낮은 걸 본다면, 충분히 더 나아질 수 있을 듯.

  3. 여러 번 테스트해본 결과, SVN의 가장 최근에 태그된 리비전이 그나마 제일 안정적이었음

  4. 클러스터 모듈의 워커들을 이용

  5. 100개의 아마존 EC2 서버들로부터 초당 10만개의 JSON HTTP GET 요청을 보냄.

  6. 클러스터 모듈을 사용해서 일시적인 요청(?) 처리의 오버헤드를 줄임. (35만 연결 중 10만개 정도가 일시적이었다) [역주] 자식 프로세스로 어떻게 뭘 분산하는지는 현재 미확인
  7. 마스터는 이전과 동일. 워커는 CPU 당 하나씩 생성하고, 마스터와는 다른 포트를 사용해서 요청을 받아서 마스터로 포워딩함. 이렇게 한 이유는 오직 1.4기가 힙 제한 때문.

V8의 1.4GB 힙제한 벗어나기

  • ulimit -n 999999: 소켓 오픈 개수 제한을 증가. 기본 1024.
  • --nouse-idle-notification: 가바지 컬렉터가 자동적으로 실행되는 걸 막음. 30초마다 4초짜리 랙이 걸리고 싶지 않으면 사용해야 함. --expose-gc 로 gc() 함수를 자바스크립트에서 직접 호출.
  • --max-old-space-size=8192 : 메모리 제한 최대값을 임의로 설정.
  • 최신 v8 소스를 약간 고쳐서 빌드: 메모리 관련 설정이나 가비지 컬렉터 실행 부분을 수정.

최근엔 1.4G 제한을 넘어서 2.2G 까지도 사용할 수 있었음. :)

[역주] node.js 서버 실행시 넘기는 파라미터:

node --trace-gc --expose-gc --nouse-idle-notification --max-new-space-size=2048 --max-old-space-size=8192 sprites.js

총평

  • 게임 서버를 개발시 이슈가 되는, 응답성, 동접 처리 등의 문제를 node.js 개발자들도 만나기 시작함. 의외로 메모리 제한이 문제가 된다는 게 특이했음. node.js 개발진은 메모리 제약은 클러스터 모듈로 분산해서 해결하는 걸 추천하는 듯.
  • 가비지 컬렉팅 문제는 응답성이 중요한 액션 게임을 개발할 경우 심각할 수 있음. (4초나 랙이 걸린다니! 그것도 30초마다!) 그래도 소셜 게임 수준은 걱정하지 않아도 될 듯.
Category:programming
Tags:node.js

comments powered by Disqus