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.

______________________

White Paper
Linux Management with Red Hat Satellite: Measuring Business Impact and ROI

Linux has become a key foundation for supporting today's rapidly growing IT environments. Linux is being used to deploy business applications and databases, trading on its reputation as a low-cost operating environment. For many IT organizations, Linux is a mainstay for deploying Web servers and has evolved from handling basic file, print, and utility workloads to running mission-critical applications and databases, physically, virtually, and in the cloud. As Linux grows in importance in terms of value to the business, managing Linux environments to high standards of service quality — availability, security, and performance — becomes an essential requirement for business success.

Learn More

Sponsored by Red Hat

White Paper
Private PaaS for the Agile Enterprise

If you already use virtualized infrastructure, you are well on your way to leveraging the power of the cloud. Virtualization offers the promise of limitless resources, but how do you manage that scalability when your DevOps team doesn’t scale? In today’s hypercompetitive markets, fast results can make a difference between leading the pack vs. obsolescence. Organizations need more benefits from cloud computing than just raw resources. They need agility, flexibility, convenience, ROI, and control.

Stackato private Platform-as-a-Service technology from ActiveState extends your private cloud infrastructure by creating a private PaaS to provide on-demand availability, flexibility, control, and ultimately, faster time-to-market for your enterprise.

Learn More

Sponsored by ActiveState