node.js에서 Heapdump를 이용한 메모리 누수 추적하기
대부분의 애플리케이션 서버들에서 고질적인 문제점중의 하나가 메모리 누수 현상이다. 비단 애플리케이션 서버에만 해당하는 문제는 아니지만 특히나 동시에 여러개의 요청을 반복적으로 받는 애플리케이션 서버의 경우에는 이 메모리 누수 현상이 훨씬 더 많이 발생한다.
node.js 의 경우, 엔진의 근간이 되는 구글 크롬 V8 자바스크립트 엔진 자체가 많은 메모리 누수 버그를 가지고 있지만, 애플리케이션에서 발생하는 메모리 누수는 발생하는 양도 크거니와 더 큰 문제를 야기할 수 있다. 이러한 애플리케이션에서의 메모리 누수를 추적하기 위한 방법을 알아보자
node.js의 확장 모듈인 heapdump는 기동중인 node.js 서버의 메모리 스냅샷을 추출할 수 있는 기능을 제공한다. 이 메모리 스냅샷을 힙덤프라고 하는데, 힙덤프에서 어떤 객체들이 메모리를 반복적으로 많이 점유하는 지를 찾아내면 메모리가 누수 되는 지점을 파악할 수 있다.
예제를 통해서 살펴보자
먼저 heapdump 모듈을 설치해야 한다. https://www.npmjs.com/package/heapdump
%npm install heapdump
명령어를 이용하여 heapdump 모듈을 설치한다.
Express로 간단한 웹 애플리케이션을 생성하자
package.json에 heapdump 모듈에 대한 의존성을 다음과 같이 추가한다.
{ "name": "MemoryLeak", "version": "0.0.0", "private": true, "scripts": { "start": "node ./bin/www" }, "dependencies": { "body-parser": "~1.13.2", "cookie-parser": "~1.3.5", "debug": "~2.2.0", "express": "~4.13.1", "jade": "~1.11.0", "morgan": "~1.6.1", "serve-favicon": "~2.3.0", "heapdump":"~0.3.7" } }
|
Figure 1 package.json에 heapdump 모듈 의존성을 추가
다음 express 프로젝트의 app.js에 아래와 같은 코드를 추가한다.
app.use('/', routes); // 기존에 자동으로 생성된 코드 app.use('/users', users); // 기존에 자동으로 생성된 코드
var heapdump = require('heapdump'); var memoryLeak = []; function LeakedObject(){ };
app.use('/leak',function(req,res,next){
for(var i=0;i<1000;i++){ memoryLeak.push(new LeakedObject()); } res.send('making memory leak. Current memory usage :' +(process.memoryUsage().rss / 1024 / 1024) + 'MB'); });
app.use('/heapdump',function(req,res,next){ var filename = '/Users/terry/heapdump' + Date.now() + '.heapsnapshot'; heapdump.writeSnapshot(filename); res.send('Heapdump has been generated in '+filename); });
|
Figure 2 메모리 누수를 유발하는 코드 및 힙덤프를 추출하는 코드 추가
/leak URL을 처리하는 부분은 인위적으로 메모리 누수를 만들어낸다. for 루프를 이용하여 LeakedObject를 1000개씩 배열에 추가하여 메모리 누수를 유발하고, 화면에 현재 메모리 사용량을 리턴하도록 하였다.
다음 /heapdump라는 URL에서는 실제로 heapdump를 생성한다. heapdump.writeSnapshot(파일명) 이라는 메서드를 사용하는데, 이 파일명 위치에 힙덤프를 저장한다.
또는 명령어를 사용하지 않더라도 프롬프트 상에서 힘덤프를 생성할 수 있다.
% kill –USR2 {node.js 프로세스 ID}
명령을 이용하면, node.js를 실행한 위치에 heapdumpxxx.heapsnapshot 이라는 이름으로 힙덤프를 생성해준다.
코드 작성이 끝났으면 애플리케이션을 실행해보자. http://localhost:3000/leak 로 들어가면 메모리 누수를 유발하고, 현재 사용중인 메모리 양을 볼 수 있다.
Figure 3 메모리 누수를 유발하는 URL에 접속
많은 메모리 누수를 유발해보기 위해서 ab (Apache benchmark : 아파치 웹서버를 설치하면 같이 설치되는 간단한 부하 테스트 툴이다. http://httpd.apache.org/) 를 이용해서 반복적으로 http://localhost:3000/leak 를 호출해보자
%ab -n 5000 http://localhost:3000/leak
명령어를 이용하면 http://localhost:3000/leak를 5000번 호출한다.
Figure 4 아파치 ab툴을 이용하여 메모리 누수를 유도하기 위해서 5000번 부하를 줌
다시 http://localhost:3000/leak 를 접속해보면 사용중인 메모리 양이 늘어난것을 볼 수 있다.
Figure 5 node.js 의 메모리 사용량이 늘어난것을 확인
이제 힙덤프를 추출해보자. http://localhost:3000/heapdump 에 접속하면 자동으로 힙 덤프가 생성된다.
이 힙덤프는 현재 node.js가 사용중인 메모리 양이 클수록 추출하는 속도가 느려진다.
Figure 6 힙덤프 추출
힙덤프 파일이 추출되었으면, 이 힙덤프를 분석하기 위해서 구글의 크롬 브라우져에서 개발자 도구를 실행해보자
개발자 도구에서 “Profiles” 탭에서 Load 버튼을 눌러서 앞에서 추출한 힙덤프 파일을 로드한다.
Figure 7 크롬 브라우져 개발자 모드에서 힙덤프 파일을 로드
힙덤프를 보면, LeakedObject라는 객체가 전체 메모리의 66%, 120MB를 점유함을 확인할 수 있다.
이 객체를 열어보면, 같은 객체가 수도 없이 반복됨을 확인할 수 있다.
Figure 8 메모리 누수를 유발한 LeakedObject를 발견
이러한 방식으로 어떤 객체들이 메모리를 많이 점유해서 메모리 누수를 유발하는지 찾아낼 수 있다.
예제 소스 코드는 https://github.com/bwcho75/nodejs_tutorial/tree/master/MemoryLeak 를 참고하기 바란다.
'클라우드 컴퓨팅 & NoSQL > Vert.x & Node.js' 카테고리의 다른 글
빠르게 훝어 보는 node.js - redis 사용하기 (ioredis 클라이언트 버전) (0) | 2016.03.30 |
---|---|
빠르게 훝어 보는 node.js - redis 사용하기 (0) | 2016.03.29 |
빠르게 훝어 보는 node.js - mongoose 스키마와 유용한 기능 (0) | 2016.03.29 |
빠르게 훝어 보는 node.js - mongoose ODM 을 이용한 MongoDB 연동 (0) | 2016.03.25 |
Heroku 클라우드에 node.js 애플리이션을 배포하기 (4) | 2016.03.21 |