Benchmarks
Unscientific(!) benchmarks:
Thinkpad T500, 3GB, core duo 2 2.4GHz.
The Java heap was limited to 64MB for this test (supplying more heap space had no measurable effect).
Minimal http/1.1 server (using low level network module):
var net = require('net');
var server = net.createServer(function (stream) {
stream.setEncoding('UTF-8');
stream.on('connect', function () {});
stream.on('data', function (data) {
//if(data.match("\r\n\r\n$"))
stream.write('HTTP/1.0 200 OK\r\nConnection: Keep-Alive\r\nContent-Type: text/html\r\nContent-Length: 12\r\n\r\nHello World\n\r\n');
});
stream.on('end', function () {stream.end();});
});
server.listen(8000, 'localhost');
Tested with: ab -k -c 100 -n 100000 http://localhost:8000/
RhiNode: 25686/sec
node.js: 25099/sec
Minimal http/1.0 server (using low level network module):
var net = require('net');
var server = net.createServer(function (stream) {
stream.setEncoding('UTF-8');
stream.on('connect', function () {});
stream.on('data', function (data) {
//if(data.match("\r\n\r\n$"))
stream.end('HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Length: 12\r\n\r\nHello World\n\r\n');
});
stream.on('end', function () {stream.end();});
});
server.listen(8000, 'localhost');
Tested with: ab -c 100 -n 100000 http://localhost:8000/
RhiNode: 8275/sec
node.js: 9022/sec
http server using the http module (includes header parsing, chunking, etc).
var http = require('http')
s = http.createServer(function(req,res) {
res.writeHead(200,{'Content-Type':'text/plain'})
res.end('Hello World\n')
});
s.listen(8000, "localhost");
console.log('Running at http://127.0.0.1:8000/')
ab -k -c 100 -n 100000 http://localhost:8000/
RhiNode: 8830/sec
node.js: 6875/sec (node.js does not honor Keep-alive without http/1.1, it would be much faster otherwise, need to find a better testing tool)
ab -c 100 -n 100000 http://localhost:8000/
Rhinode: 4119/sec
node.js: 6872/sec
Same with content-length specified (instead of chunking):
var http = require('http')
s = http.createServer(function(req,res) {
res.writeHead(200,{'Content-Type':'text/plain','Content-length':'12'})
res.end('Hello World\n')
});
s.listen(8000, "localhost");
console.log('Running at http://127.0.0.1:8000/')
ab -k -c 100 -n 100000 http://localhost:8000/
RhiNode: 10025/sec
node.js: 15692/sec
ab -c 100 -n 100000 http://localhost:8000/
RhiNode: 4073/sec
node.js: 6917/sec
The lowlevel networking code is already quite fast (still, the main event loop runs in Javascript and interfaces with Java through the reflection, so that can be sped up significantly). The HTTP module is slow for two reasons:
- It is written as a pure client to the NET module.
- http protocol state is managed with Javascript generator functions, which provide for simple, easy to understand code, but are relatively slow to setup. This is mostly evident in the slower http/1.0 numbers (where a new generator needs to be setup for each request).
So in addition to implementing the event loop and some other tight loops in Java, the HTTP modules can benefit from a more direct API into the network layer and from caching the Generator function between sockets (or by removing them, and use a low level state machine instead at the expense of readability).