At the Forge - Node.JS

Want to write high-performance network server applications? Node.JS uses JavaScript to do exactly that.
Installation

Although it's common to think of Node.JS as a JavaScript program, it's actually an engine on top of which JavaScript programs run. Node.JS itself is actually an executable you must install onto your machines.

I'm normally a big fan of Ubuntu's packaging mechanism, which allows me to use apt-get install to fetch and install whatever software I want. Node.JS isn't yet available for Ubuntu 9.10, which I have running on my server, so I was forced to install it from source. Fortunately, that's quite simple to do, especially if you're familiar with the Git version-control system. First, I cloned the repository from GitHub:

git clone git://github.com/ry/node.git

Then, I compiled Node.JS by going into the node directory and running the standard commands for compiling source:


cd node
./configure && make && make test && make install

Note that when you compile Node.JS, you're compiling a program that includes the V8 JavaScript engine, so don't be surprised if it takes a while to compile on your machine. The default installation goes under /usr/local/, including /usr/local/lib/node, /usr/local/include/node and (for the executable) /usr/local/bin/node.

Now that it's installed, what can you do? Well, the traditional thing to do in any programming language is a “Hello, world” program. So let's look at one (modified from an example in the Node.JS documentation):

var http = require('http');

http.createServer(function (request, response) {
        var startTime = new Date().getTime();
    response.writeHead(200, {'Content-Type': 'text/plain'});
    response.write("line 1\n");
    response.end('Hello World\n');
    var elapsedTime = new Date().getTime() - startTime;
    console.log("Elapsed time (in ms): " + elapsedTime);
}).listen(8124);

console.log('Server running at http://127.0.0.1:8124/');

The first thing that comes to mind when I look at code like this is, “Wow, JavaScript can look like any other language!” Perhaps that's an odd thing to think or say, but I'm so used to seeing JavaScript inside an HTML page or (better yet) in a file of its own but inside unobtrusive document-ready blocks in jQuery, that seeing a server-side JavaScript program that doesn't reference the DOM even once is a new and strange experience.

The first line uses the require function, provided by CommonJS. CommonJS is an API that attempts to fill in the gaps left by the JavaScript standard, now that JavaScript is used beyond the browser. There are a number of implementations of the CouchJS standard, of which one is in Node.JS. One of the most useful aspects of the specification has to do with modules, allowing you to do in JavaScript what's taken for granted in other languages—putting a number of function and variable definitions into a file and then importing that file via a reference name into a program. With CommonJS installed, the require function is, thus, available. The first line puts all of the definitions from the http module into our http variable.

With that in place, you invoke the http.createServer function. This function takes one parameter—a function that itself takes two parameters: a request and a response. The request object contains everything you would expect in an HTTP request, including headers, parameters and the body. The response object, which is created by the server, contains the actual response headers and data.

If you are new to JavaScript, it might seem a bit odd that I'm passing a function as a parameter. (And, if you're not used to anonymous functions, you had better start now!) But I'm also not directly invoking that function. Rather, this is the way you tell Node.JS that when an HTTP request comes in via the server, your function should be invoked—and the HTTP request should be passed to the function's first parameter.

Indeed, this style is at the heart of Node.JS. You typically don't invoke functions directly. Rather, you tell the underlying infrastructure that when a request comes in, such and such a function should be invoked. This use of “callbacks” is already somewhat familiar to anyone who has used JavaScript in a browser. After all, a client-side JavaScript program is nothing more than a bunch of callbacks. But in the server context, it seems a bit different, at least to me.

Now, what does this callback function do? First, it gets the current time, in milliseconds and stores it in a variable (startTime). I'll use it later on to find out how long the execution took.

The callback then uses the built-in functions that have been defined for the response object to send data back to the user's browser. Several methods are available to use. response.writeHead sends the HTTP response code, as well as one or more HTTP headers, passed as a JavaScript object. response.write (which should be invoked only after response.writeHead) sends an arbitrary string to the user's browser. The response to the user needs to finish with a call to response.end; if you include a string as a parameter, it's the same as calling response.write with that string, followed by response.end.

The final thing that this function does is print, on the console, the number of milliseconds that have elapsed since it first was invoked. Now, this might seem a little silly when using a toy program like this one. But even when I used ApacheBench to make 10,000 total requests with 1,000 of them happening concurrently, Node.JS kept chugging along, handling each of these requests in either 0 or 1ms. That's pretty good from my perspective, and it matches the extreme performance others have reported with Node.JS, even on more sophisticated programs.

The call to createServer returns an HTTP server object, which I then instruct to listen on port 8124. From that point on, the server is listening—and each time it receives an HTTP request, it invokes the callback. At any given time, Node.JS is handling many simultaneous connections, each of which is sending or receiving data. But as a single-process, single-thread program, Node.JS isn't really doing all of this simultaneously. Rather, it's doing its own version of multitasking, switching from one task to another inside its own program. This gives Node.JS some pretty amazing speed.

______________________

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix