Finding Memory Leaks and CPU Usage in Azure Node.js Web App
Slow application performance issues tend to be challenging to troubleshoot regardless of the platform in which your application is running. This is due in great part to the sometimes random nature of these issues. These types of issues also often do not result in a specific error being logged.
If you think your node.js application is running slow and takes more than few seconds to receive response. Below info may help you analyze where it's taking longer time and also checks for memory leaks. There are many node.js modules to accomplish this(notably)
- v8-profiler
- nodetime(app dynamics)
- look
If you analyze below sample code, I have included memory leak highlighted in Red and CPU intensive work in Amber colors.
/**
* Created by prmadi on 8/20/2015.
*/
var http = require('http');
var port = process.env.PORT || '3000';
// Memory Leak
function LeakingClass() {
}
var leaks = [];
setInterval(function() {
for (var i = 0; i < 100; i++) {
leaks.push(new LeakingClass);
}
console.error('Leaks: %d', leaks.length);
}, 1000);
http.createServer(function (req, res) {
// CPU intensive work
var fibonacci = function(n){
if(n < 1){return 0;}
else if(n == 1 || n == 2){return 1;}
else if(n > 2){return fibonacci(n - 1) + fibonacci(n-2);}
};
fibonacci(40);
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n'+ fibonaccif(40));
}).listen(port, '127.0.0.1');
I would show you how to use v8-profiler on above sample code to find memory leaks and CPU Usage. More info on v8-profiler can be found @ https://github.com/node-inspector/v8-profiler
- Install v8-profiler module using below command in kudu console at webapp root(D:\home\site\wwwroot) or enter it in package.json file before deploying to azure web apps.
npm install v8-profiler
- Create a folder "debugdump" in your webapp root(D:\home\site\wwwroot).
- Add below lines of code to get heap snapshot
var fs = require('fs'),
ws = fs.createWriteStream('debugdump/'+Date.now() + '.heapsnapshot'),
profiler = require('v8-profiler'),
snapshot = profiler.takeSnapshot(),
callback = ws.end.bind(ws);
snapshot.serialize(function(data) {
ws.write('' + data);
}, callback);//begin cpu profiling
- Add below lines of code to get CPU profile
profiler.startProfiling();
// code to be profiled here
var cpuProfile = profiler.stopProfiling();
var serialized = JSON.stringify(cpuProfile, null, 2);
fs.writeFileSync('debugdump/'+Date.now() +'.cpuprofile', serialized, 'utf8');
- After accessing your application, you would start seeing few files with cpuprofile and heapsnapshot extensoins in D:\home\site\wwwroot\debugdump folder.
- Download files in debugdump folder and analyze them using tools like chrome developer tools.
Here is my sample code after adding profiler instructions listed above
/**
* Created by prmadi on 8/20/2015.
*/
var http = require('http');
var port = process.env.PORT || '3000';
function LeakingClass() {
}
var leaks = [];
setInterval(function() {
for (var i = 0; i < 100; i++) {
leaks.push(new LeakingClass);
}
}, 1000);
http.createServer(function (req, res) {
var fs = require('fs'),
ws = fs.createWriteStream('debugdump/'+Date.now() + '.heapsnapshot'),
profiler = require('v8-profiler'),
snapshot = profiler.takeSnapshot(),
callback = ws.end.bind(ws);
snapshot.serialize(function(data) {
ws.write('' + data);
}, callback);//begin cpu profiling
var fibonacci = function(n){
if(n < 1){return 0;}
else if(n == 1 || n == 2){return 1;}
else if(n > 2){return fibonacci(n - 1) + fibonacci(n-2);}
};
profiler.startProfiling();
fibonacci(40);
var cpuProfile = profiler.stopProfiling();
var serialized = JSON.stringify(cpuProfile, null, 2);
fs.writeFileSync('debugdump/'+Date.now() +'.cpuprofile', serialized, 'utf8');
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n'+ fibonacci(40));
}).listen(port, '127.0.0.1');
- Above code has created few CPU profiles and heap snapshots in my debugdump folder as in below screenshot.
- Load these files into chrome developer tools by selecting chrome developer tools > profiles > load
- Below is a sample heap snapshot analysis screenshots. As you can see, Leakclass was the culprit in my above sample code which is visible in heap snapshot.
- Below is a sample CPU Usage analysis. As you can see, calculating fibonanci number was CPU intensive operation in my request which is visible in CPU profile.
Chart View :
Heavy (Bottom Up) View :
Comments
Anonymous
October 19, 2015
This is actually the first decent info I have found on the topic, but it leaves out one little bit that seems important for those of us not on the Windows platform (which is everyone at my company): How do I create a folder in the webapp? It seems as if you hint at doing it outside of the app, otherwise I am sure we could use some kind of file system call from the Node process. The other thing is how to retrieve those files again using the azure CLI tools.Anonymous
January 10, 2016
Hi Carl,Are you planning to create this folder manually using ftp/kudu console (https://Your_Website_name.scm.azurewebsites.net/DebugConsole).If you want create it using node.js mkdrip(https://www.npmjs.com/package/mkdirp) is something i generally use but there are many other too.- Anonymous
January 11, 2016
It was more of a comment on the article than an actual question of how to do it. I think it is an omission not to list a few ways of doing things when you casually mention stuff like> "Create a folder “debugdump” in your webapp root(D:\home\site\wwwroot).Most of the article is pretty forwards, but a lot of people using Azure have no idea that Kudu even exists or what it is. I think it would improve the article to say something like "There are many ways of creating folders and retrieving files, but one easy way that alleviates you from implementing it in code is using Kudu. Kudu gives you web based interface for folder and file manipulation, and it can be accessed by prepending .scm before your hostname in the full url to your host. E.g. myapp.scm.azurewebsites.net".Often people will stop at these quite simple steps, and I was unsure of whether you meant doing these steps by FTP, Kudu, the Azure CLI or programmatically. So expanding the article a bit will make it more helpful :-)
- Anonymous