In this article we are going to address basic question which might occur in minds of green web-programmers and those who is going to dive into Node.js learning, namely:
And the performance tests at the end of the article will try answer a reasonable question “Why would I need to learn Node.js.”
So, let’s start…
Node.js is an event-oriented Javascript-based framework for development of web applications. The core concept is that nothing gets blocked during code execution – operations waiting for data transfer, data input, connection establishment or anything else are not present. Everything is based on events, which occur at the moment synchronous operations are waiting for. This sometimes leads to dramatic—dozens of times—performance boost in comparison with old sync systems. With the release of version 0.6.0 of November 2011 Node.js assembly for Windows in announced stable.
To begin it’s necessary to download and install Web Platform Installer, run it, click Options and put Helicon Zoo Feed link http://www.helicontech.com/zoo/feed/ into “Display additional scenarios” field:
This adds Zoo tab in Web Platform Installer:
Under Zoo -> Engines there’s a list of all available web engines, including Node.js. However, we recommend opting for Node.js Package which incorporates not only Node.js itself but also several highly useful modules. So, got to Zoo -> Packages -> Node.js Hosting Package and do Add, Install.
To see all currently supported web frameworks and applications visit Helicon Zoo Gallery. After you agree to the license agreements, it starts downloading and installing IIS (if not yet there), Helicon Zoo Module and node.exe for Windows.
An important system component is Node Package Manager (npm) used for installation of additional modules. Starting from version 0.6.5 of Node.js Node Package Manager declared stable and now is included into Node.js Hosting Package.
Now Node.js is installed and to start doing applications for it it’s reasonable to use WebMatrix templates. These templates simplify creation of blank draft apps which might be used for further development.
To install them follow: Zoo -> Packages -> WebMatrix Templates
If you don’t have WebMatrix – not to worry – it will be downloaded and installed automatically together with installation of templates. After the installation run WebMatrix and choose «Site from Template»:
As you can see, Node.js is not the only framework favoring from WebMatrix templates.
If you follow the URL of the newly created Node.js Site or press Run, you get common «Hello, World!» page.
By default the new site includes framework express for easy web-apps creation. The framework and its dependencies reside in node_modules folder under the site root which is good for deployment of the app on remote server.
The folder “public” is used to store static files. Any file put into this folder will be processed directly by IIS as static, not evoking Node.js. This is especially important to avoid accidental execution of client *.js files on the server.
web.config file contains URL Rewrite rules for static content. Initially every request is checked against the content of public folder (i.e. whether it’s static). This is beneficial for some web apps which mix static and dynamic resources in one folder (often root). If your app is not doing so, you can delete Microsoft URL Rewrite rules from web.config and refer to static files by explicitly specifying public folder.
Additionally, web.config includes configuration directives required for launch of Node.js and Helicon Zoo Module on that site.
One of the advantages of Node.js is that JavaScript is a popular language widely used in web development. It means you won’t have problems choosing the editor. Free WebMatrix editor is ok to start with.
To illustrate capabilities of asynchronous web frameworks most write a chat. So, the most known demo-app for Node.js is a chat http://chat.nodejs.org/, its source code is available for examination.
We’ve also decided to make a chat – very primitive one – with no users, no sessions, no scrolls and message editing. It can only transmit asynchronous messages to show how long-polling works.
We’ll make use of previously-created Node.js Site. We need to edit server.js and index.html.
Here’s the source code for server.js:
var express = require('express');
var callbacks = [];
// Sends messages to clients
function appendMessage(message){
var resp = {messages: [message]};
while (callbacks.length > 0) {
callbacks.shift()(resp);
}
}
// Creation of express server
var app = module.exports = express.createServer();
app.use(express.bodyParser());
// Simply respond with index.html
app.get('/', function(req, res){
res.sendfile('index.html');
});
// Process messages from client
app.post('/send', function(req, res){
var message = {
nickname: req.param('nickname', 'Anonymous'),
text: req.param('text', '')
};
appendMessage(message);
res.json({status: 'ok'});
});
// Wait for new messages
app.get('/recv', function(req, res){
callbacks.push(function(message){
res.json(message);
});
});
// Listen to the port
app.listen(process.env.PORT);
and index.html
<html>
<head>
<title>Node.js Zoo Chat</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
// Initialization after page load
$(document).ready(function(){
$('form#send').submit(onSend);
longPoll();
$('#nickname').focus();
});
// Send message on pressing Submit
function onSend(eventData){
eventData.preventDefault();
var msgArr = $(this).serializeArray();
var message = {
nickname : msgArr[0].value,
text : msgArr[1].value
};
$.post('/send', message, function (data){
$('#text').val('').focus();
},
'json');
}
// Called when new message is available
function longPoll(data){
if (data && data.messages) {
for (var i = 0; i < data.messages.length; i++) {
var message = data.messages[i];
$('<p><b>'+message.nickname+':</b><span>'+message.text+'</span></p>').hide().prependTo('#messages').slideDown();
}
}
// message processed, wait for new messages
$.ajax({
cache: false,
type: "GET",
url: "/recv",
success: function(data){
longPoll(data);
}
});
}
</script>
</head>
<body>
<h1>Node.js Zoo Chat</h1>
<form action="/send" method="post" id="send">
<label for="nickname">Nickname:</label> <input name="nickname" size="10" id="nickname" />
<label for="text">Message:</label> <input name="text" size="40" id="text" />
<input type="submit">
</form>
<div id="messages"></div>
</body>
</html>
To apply changes press Restart and then Run:
Now we can make sure the chat works by running it in two browsers:
The flexibility and usability of each web framework may probably be defined by availability of extra modules and applicability of third-party technologies. At present Node Package Manager declared stable for Windows, so you ca use it safely for modules installations. NPM is included in Node.js Hosting Package and we have plans to include it into Node.js engine installation itself very soon – just as new Node.js MSI installer will be applicable to use in Helicon Zoo repository. And there’s one trick to remember – by default npm installs modules to node_modules folder under the folder it was invoked from. This is good for further application deployment on remote server as all required modules are included into application folder itself. Thus, to install module for site, go to the site root and execute:
C:\>cd "C:\My Web Sites\Node.js Site" C:\My Web Sites\Node.js Site>C:\node\npm.cmd install mongodb npm WARN [email protected] package.json: bugs['web'] should probably be bugs['url'] > [email protected] install C:\My Web Sites\Node.js\node_modules\mongodb > node install.js ================================================================================ = = = To install with C++ bson parser do <npm install mongodb --mongodb:native> = = = ================================================================================ [email protected] ./node_modules/mongodb
Another thing worth mentioning is that no all existing modules work for Windows. E.g. the perfect node-sync library won’t work for Windows. This library helps avoid monstrous callbacks paradigm without losing Node.js asynchronous nature, but it relies on node-fibers, which do not work on Windows. Hopes are that in future fibers will be implemented directly into Node.js.
Nevertheless, most modules are fully operational on Windows.
If you start working on a more or less complex Node.js project, sooner or later you’ll come to a conclusion that JavaScript is not that friendly. Tons of braces, loads of unnecessary constructions – all that stuff doesn’t add to code readability and makes code management more complicated. Luckily, you are not the first one to notice that, so the problem is already solved. There are many derivative languages based on JavaScript or extending it. Here’s a short list FYI: http://altjs.org/
We take CoffeeScript as the trendiest for now. Code written with CoffeeScript is simple and easy to read. This code is then compiled into original JavaScript and executed. Moreover, JavaScript code may be converted into CoffeeScript. For example, server.js script from our chat in CoffeeScript becomes this:
express = require("express")
callbacks = []
// Sends messages to clients
appendMessage = (message) ->
resp = messages: [ message ]
callbacks.shift() resp while callbacks.length > 0
// Creation of express server
app = module.exports = express.createServer()
app.use express.bodyParser()
// Simply respond with index.html
app.get "/", (req, res) ->
res.sendfile "index.html"
// Process messages from client
app.post "/send", (req, res) ->
message =
nickname: req.param("nickname", "Anonymous")
text: req.param("text", "")
appendMessage message
res.json status: "ok"
// Wait for new messages
app.get "/recv", (req, res) ->
callbacks.push (message) ->
res.json message
// Listen to the port
app.listen process.env.PORT
Learn more about CoffeeScript: http://jashkenas.github.com/coffee-script/
To install CoffeeScript run: C:\node\npm.cmd install coffe-script
There’s a good tool for Node.js apps debugging — node-inspector. It is already included into node_modules folder in template of Node.js-site. node-inspector works as follows:
In root folder of template-based node.js-site there’s start_debug.cmd file which runs debugging for current app and opens pages in the browser for debugging.
This is how debugger looks in the browser:
Now we have an app and want to put in online. What we need is a server, and now putting together Windows server and Node.js is easy as never before. We only need to go through several steps we did at the beginning of the article (which we used to deploy working environment). Namely: install Microsoft Web Platform Installer, add Helicon Zoo feed into it and set up Node.js Hosting Package from Zoo repository. Done – server is ready to run our app. Server platforms supported include Windows 2008 and 2008 R2, x86 and x64.
What needs to be done next is create blank web-site on the server using IIS or hosting panel (if we are creating our own hosting) and copy the app into the site with FTP or WebDeploy. In case of WebDeploy all necessary permissions for the folders will be assigned. One can also use Git or any other version control system, but that goes beyond the scope of this article.
Initially, Helicon Zoo Module was being developed for configuration of hosting solutions. And all applications within Zoo are separate and do not interfere. The module itself with default settings operates in automatic mode creating one worker process, when the load is low, or bearing new workers (up to the number of processor cores) to ensure maximum performance when the load goes up.
Helicon Zoo adopts the concept of engines and applications. Engines define what to run and how, using which protocol and port, min and max number of workers allowed and other general settings, which are specified globally in applicationHost.config. Then under the site you can create an application relying on a particular engine and pass all parameters required for its flawless operation. This helps isolate hosting administrator work from clients and clients from each other.
Testing server characteristics: Core 2 Quad 2.4 GHz, 8 Gb RAM, 1Gb LAN. For load generation we used more powerful machine and Apache Benchmark command «ab.exe -n 100000 -c 100 –k». To test Apache and Nginx we took Ubuntu 11.04 Server x64. IIS 7 tests ran on Windows Server 2008 R2. Nothing virtual — 100% hardware.
We’ve conducted 3 tests. In the first one Node.js was supposed to output current time in high resolution. Time was chosen to be sure responses didn’t come from cache. Second test implied reading from MySQL database, third one — writing to DB.
Here are the results (values on the graph mean requests per second):
Impressive, isn’t it? Time to explain what these tests measure. It’s not entirely correct to call them performance tests as we do not compare different processors. While processor may have performance, web server measurement unit is quite the contrary — how much processor time it takes to process one request.
The first test measures raw expenses on request processing for each web-server and their ability to use processor resources. There’s no way this or that set of technologies can respond faster on this processor. Nginx on Windows was far behind on this test because on this system Nginx opens new connection to back-end upon each request. While Apache on Windows surprised with connection pooling and true threads.
The second and third test show how web-server expenses grow with the “weight” of request. However, they are influenced by a number of other factors, such as performance of file system, DB drivers and the DB itself. Out of curiosity we’ve tested the joint Windows + Zoo + MongoDB to see the difference with MySQL. And it gave 6793 rps for reading and 2906 rps for writing. Writing speed is truly amazing.
Another interesting fact is that software and hardware used in these tests is absolutely the same as in Django tests in this article. So their results may be compared. Undoubtedly Node.js scripts are much more light-weight, we didn’t use templates, ORM etc,, but anyway it’s worth thinking about.
Responding to readers’ requests we are posting detailed ab graphs. We’ve re-done the first test with simple time output, ‘case it most verbosely depicts web server operation. Config files and js scripts being tested may be downloaded from here. There are only includes, everything else left by default. Horizontal axis shows requests, vertical one — response time in milliseconds.
Windows, IIS7 + Zoo, “time output”:
Ubuntu, Apache, “time output”:
Ubuntu, Nginx, “time output”:
I believe that Node.js is a rather promising trend. It boasts great performance and flexibility. What is especially pleasing is that it’s equally good on both Unix and Windows and uses relevant technological solutions for each system which the tests vividly prove.
Support of Erlang and Java in Helicon Zoo is on the way. It will be of interest to compare performance of these technologies as well. For now Node.js is an unquestionable leader in performance among supported frameworks.
]]>