Connect - Middleware For NodeJS
Yesterday myself and Tim Caswell open-sourced
the first Ext JS nodejs project, Connect.
Connect is an abstraction layer, providing node developers with an effective, high performance solution
for rapid development using interchangable components called “middleware”.
Middleware
Middleware provides node developers with simple “plug and play” modules,
which may be stacked in any order desired, aiding in rapid development. Connect
middlware are regular node modules exporting the handle() method, however conceptually
they fall into two categories, filters, and providers.
A “filter” conceptually sits arbitrarily within the middlware stack,
processing incoming and outgoing traffic, but typically does not respond
to a request. An example of this is the log filter
provided by Connect, it does not respond to any request, it simply proxies
function calls in order to log request data.
A “provider” differs conceptually in the fact that it provides an end-point
in the stack. However this may not always be the case. For example a json-rpc
provider may choose not to process or respond to a request if the Content-Type header
is not application/json. A classical example of a provider is the static provider
which serves static files.
Executable
Connect is a dual purpose library, rapid development is not the only goal in mind.
Also provided is the connect executable which can be used to daemonize Connect servers
(and regular node servers) using an extremely simple command-line interface.
For more information on the connect executable install Connect and run:
$ man connect
Performance
Performance is a top priority for Connect, and we have the benchmarks to prove it.
The following benchmarks were performed with ApacheBench,
node 0.1.97, thin 1.2.7, sinatra 1.0, and rack 1.1.0.
The benchmarks bundled with Connect consistently showed that
the library has nearly no overhead compared to a regular node
server when responding with the typical “Hello World” response.

Next up we have node, sinatra (thin), and Connect serving jquery.js,
a roughly ~57kb.

If you wish to run the benchmarks on your own machine, first execute:
$ make benchmark
Then generate the graphs with gnuplot:
$ make graphs
Once complete:
$ open results/graphs
Conclusion
Connect is awesome, what are you waiting for! head over to the Github repo and fork away.
Express vs Sinatra Benchmarks
So I have been setting up benchmark scripts for Express today, and so far some of the results have been quite interesting! The numbers shown should be taken lightly, however they consistently show that Express is quite fast.
If you are interested in benchmarking your own web applications you might want to read my last article ApacheBench Gnuplot Graphing Benchmarks.
All of the following benchmarks were generated using ApacheBench with a concurrency of 50 and performs 2000 requests. Keep in mind that Thin is used to serve Sinatra requests.
Express vs Sinatra
For those who dont know Express is a NodeJS framework inspired by Ruby’s Sinatra. Below we have the benchmark results for a typical “Hello World” response, which include nodejs benchmarks without the overhead of features provided by Express:


Haml.js vs Ruby Haml
Next up is my JavaScript Haml implementation. Below are the results of running Express & haml.js vs Sinatra & Haml. Both serve a layout template, as well as a page specific template.


Sass.js vs Ruby Sass
Finally we have JavaScript Sass vs the regular Ruby implementation packaged with haml. Both implementations serve the same 80 line stylesheet.


Stay tuned for more benchmarks!
ApacheBench GnuPlot Graphing Benchmarks
In this post I am going to be showing you how you can get set up creating http benchmark graphs using Gnuplot and ApacheBench. The ApacheBench or ab executable is packaged with Apache’s httpd, however it can be installed stand-alone as well from Google Code.
The Application
First things first, below we have an insanely simple NodeJS application, that will respond with the string Hello World, nothing fancy.
var sys = require('sys'),
http = require('http');
var body = 'Hello World'
http.createServer(function(request, response) {
response.writeHead(200, {
'Content-Type': 'text/plain',
'Content-Length': body.length
});
response.end(body, 'ascii');
}).listen(8000);
sys.puts('Server running at http://127.0.0.1:8000/')
Benchmarking
There are several ways to customize ApacheBench, however for this post we are going to keep things simple and simply hit the server with 8000 requests, with a concurrency of 100:
$ ab -n 8000 -c 100 http://127.0.0.1:8000/
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/
Benchmarking 127.0.0.1 (be patient)
Completed 800 requests
Completed 1600 requests
Completed 2400 requests
Completed 3200 requests
Completed 4000 requests
Completed 4800 requests
Completed 5600 requests
Completed 6400 requests
Completed 7200 requests
Completed 8000 requests
Finished 8000 requests
Server Software:
Server Hostname: 127.0.0.1
Server Port: 8000
Document Path: /
Document Length: 11 bytes
Concurrency Level: 100
Time taken for tests: 1.340 seconds
Complete requests: 8000
Failed requests: 0
Write errors: 0
Total transferred: 760285 bytes
HTML transferred: 88033 bytes
Requests per second: 5970.16 [#/sec] (mean)
Time per request: 16.750 [ms] (mean)
Time per request: 0.167 [ms] (mean, across all concurrent requests)
Transfer rate: 554.08 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 3 1.7 3 9
Processing: 4 14 3.7 13 30
Waiting: 3 12 4.0 12 29
Total: 8 17 2.5 16 30
Percentage of the requests served within a certain time (ms)
50% 16
66% 17
75% 18
80% 18
90% 20
95% 21
98% 23
99% 25
100% 30 (longest request)
Benchmarks like these are not overly practical but can provide insight to how well a server can respond when being hit with the same request. The results above will certainly vary depending on your system, the resources available, etc.
Graphing
Now although the report generated is helpful, we need to output the data in a parse-able format. To do this we use the -g switch which will output a gnuplot-friendly tab delimited table of data. Note that -e is available and will output CSV data for those of you wishing to generate graphs in programs like excel (fuck! microsoft sucks).
Run your benchmarks again to generate out.dat (note the filename is not important, out.txt etc is fine):
$ ab -n 8000 -c 100 -g out.dat http://127.0.0.1:8000/
We can now either generate graphs using gnuplot’s shell, or we can create a script that we can re-use to generate the graph. When playing around with customizing the graph, I would recommend using the shell which can be started by invoking gnuplot with no args:
$ gnuplot
gnuplot> set title "My Benchmark"
gnuplot> plot "out.dat" using 9
Or as I mentioned we can use a plot script which can be re-used easily. Mine typically looks something like the annotated version below (saved as plot.p):
# output as png image
set terminal png
# save file to "out.png"
set output "out.png"
# graph title
set title "ab -n 8000 -c 100"
# nicer aspect ratio for image size
set size 1,0.7
# y-axis grid
set grid y
# x-axis label
set xlabel "request"
# y-axis label
set ylabel "response time (ms)"
# plot data from "out.dat" using column 9 with smooth sbezier lines
# and title of "nodejs" for the given data
plot "out.dat" using 9 smooth sbezier with lines title "nodejs"
And generate the graph with:
$ gnuplot plot.p

Graphing Several Data Sets
Plotting several data-sets is helpful when comparing various servers etc, so lets change up our nodejs server a bit. Below we wrap the response with a 0-1000 millisecond setTimeout() to vary the results.
var sys = require('sys'),
http = require('http');
var body = 'Hello World'
http.createServer(function(request, response) {
setTimeout(function(){
response.writeHead(200, { 'Content-Type': 'text/plain', 'Content-Length': body.length });
response.end(body, 'ascii');
}, Math.floor(Math.random() * 1000))
}).listen(8000);
sys.puts('Server running at http://127.0.0.1:8000/')
Now execute the same ab command, however change out.dat to out2.dat, and add a line to plot.p which tells gnuplot to use “out2.dat” for the second set of data.
plot "out.dat" using 9 smooth sbezier with lines title "nodejs", \
"out2.dat" using 9 smooth sbezier with lines title "nodejs random timeout"
Now run the gnuplot command again to generate the png image:

Automation
So far our data has been pretty static, however a bash script can easily be used to generate the plot script dynamically. A simple example of this can be seen in the Express benchmarks used to generate graphs against node, express, thin, etc.
Hope that helps some of you guys!