Skip to content

Instantly share code, notes, and snippets.

@jmervine
Created October 20, 2013 19:54
Show Gist options
  • Save jmervine/7074460 to your computer and use it in GitHub Desktop.
Save jmervine/7074460 to your computer and use it in GitHub Desktop.
SSL Test Node.js/SPDY/Express.js vs. Nginx/SPDY vs. Nginx/SPDY -> Node.js/Express.js

HTTPS Test using SPDY

Node.js+node-spdy vs Nginx+SPDY

This is by no means a comprehensive test. It was done a laptop with a dump of Google's homepage as the content. Performance data was generated using 10000 connections to localhost using `httperf'. If you see any glaring holes though, please point them out. Cheers!

Findings summary:

  1. Node.js / node-spdy / Express.js: avg 139.1
  2. Nginx / SPDY -> Node.js / Express.js: avg 150.1
  3. Nginx / SPDY: avg 231.3

Node.js / node-spdy / Express.js

The node test was used running node-spdy and express on Node.js v0.10.20.

Code

var spdy = require('spdy');
var express = require('express');
var fs = require('fs');

var options = {
  key: fs.readFileSync(__dirname + '/server.key'),
  cert: fs.readFileSync(__dirname + '/server.crt'),
  ca: fs.readFileSync(__dirname + '/server.csr'),
  windowSize: 1024
};

var app = express();
app.use(express.logger());
app.get('/', function(req,res) {
    fs.readFile(__dirname+'/google.html', function(err, data) {
        if (err) {
            console.trace(err);
            res.send(500);
        } else {
            res.setHeader('Content-Type', 'text/html');
            res.setHeader('Content-Length', data.length);
            res.end(data);
        }
    });
});

var server = spdy.createServer(options, app);
server.listen(8443);

Results

httperf --client=0/1 --server=localhost --port=8443 --uri=/ --send-buffer=4096 --recv-buffer=16384 --ssl --ssl-no-reuse --num-conns=10000 --num-calls=1
httperf: warning: open file limit > FD_SETSIZE; limiting max. # of open files to FD_SETSIZE
Maximum connect burst length: 1

Total: connections 10000 requests 10000 replies 10000 test-duration 71.998 s

Connection rate: 138.9 conn/s (7.2 ms/conn, <=1 concurrent connections)
Connection time [ms]: min 6.1 avg 7.2 max 60.1 median 6.5 stddev 1.6
Connection time [ms]: connect 5.8
Connection length [replies/conn]: 1.000

Request rate: 138.9 req/s (7.2 ms/req)
Request size [B]: 62.0

Reply rate [replies/s]: min 119.4 avg 139.1 max 145.0 stddev 6.8 (14 samples)
Reply time [ms]: response 1.3 transfer 0.0
Reply size [B]: header 151.0 content 18605.0 footer 0.0 (total 18756.0)
Reply status: 1xx=0 2xx=10000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 24.38 system 47.41 (user 33.9% system 65.9% total 99.7%)
Net I/O: 2552.4 KB/s (20.9*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

Nginx / SPDY Module

Nginx info:

[jmervine@laptop] ~/Development/nginx $ /home/jmervine/tmp/nginx/sbin/nginx -V
nginx version: nginx/1.4.3
built by gcc 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) 
TLS SNI support enabled
configure arguments: --with-http_ssl_module --with-http_spdy_module --prefix=/home/jmervine/tmp/nginx

Config

worker_processes  1;
events {
    worker_connections  1024;
}

http {
    include            /home/jmervine/tmp/nginx/conf/mime.types;
    default_type       text/html;
    sendfile           on;
    keepalive_timeout  65;

    server {
        listen              8443 ssl spdy;
        server_name         localhost;
        ssl_certificate     /home/jmervine/Development/ssltest/server.crt;
        ssl_certificate_key /home/jmervine/Development/ssltest/server.key;

        location / {
            root  /home/jmervine/Development/ssltest/;
            index google.html;
        }
    }
}

Results

httperf --client=0/1 --server=localhost --port=8443 --uri=/ --send-buffer=4096 --recv-buffer=16384 --ssl --ssl-no-reuse --num-conns=10000 --num-calls=1
httperf: warning: open file limit > FD_SETSIZE; limiting max. # of open files to FD_SETSIZE
Maximum connect burst length: 1

Total: connections 10000 requests 10000 replies 10000 test-duration 43.225 s

Connection rate: 231.3 conn/s (4.3 ms/conn, <=1 concurrent connections)
Connection time [ms]: min 4.0 avg 4.3 max 8.3 median 4.5 stddev 0.6
Connection time [ms]: connect 4.0
Connection length [replies/conn]: 1.000

Request rate: 231.3 req/s (4.3 ms/req)
Request size [B]: 62.0

Reply rate [replies/s]: min 228.6 avg 231.3 max 233.2 stddev 1.3 (8 samples)
Reply time [ms]: response 0.3 transfer 0.0
Reply size [B]: header 240.0 content 18605.0 footer 0.0 (total 18845.0)
Reply status: 1xx=0 2xx=10000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 19.31 system 23.85 (user 44.7% system 55.2% total 99.8%)
Net I/O: 4271.6 KB/s (35.0*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0

Nginx/SPDY Module -> Node.js/Express.js

I ran the test, under the assumption that nginx had already failed and this was going to fail worse. That said, this is the more apples to apples compairison to the first test, as this is closer to what I would really be doing in production. Suprisingly, it was faster then I expected. I can only assume that node's readFile (async) method is more efficent that nginx in reading files off disk, which would be shocking.

Code

var express = require('express');
var fs = require('fs');

var app = express();
app.use(express.logger());
app.get('/', function(req,res) {
    fs.readFile(__dirname+'/google.html', function(err, data) {
        if (err) {
            console.trace(err);
            res.send(500);
        } else {
            res.setHeader('Content-Type', 'text/html');
            res.setHeader('Content-Length', data.length);
            res.end(data);
        }
    });
});
app.listen(8000);

Config

worker_processes  1;
events {
    worker_connections  1024;
}

http {
    include            /home/jmervine/tmp/nginx/conf/mime.types;
    default_type       text/html;
    sendfile           on;
    keepalive_timeout  65;

    server {
        listen              8443 ssl spdy;
        server_name         localhost;
        ssl_certificate     /home/jmervine/Development/ssltest/server.crt;
        ssl_certificate_key /home/jmervine/Development/ssltest/server.key;

        location / {
            proxy_pass http://localhost:8000;
        }
    }
}

Results

httperf --client=0/1 --server=localhost --port=8443 --uri=/ --send-buffer=4096 --recv-buffer=16384 --ssl --ssl-no-reuse --num-conns=10000 --num-calls=1
httperf: warning: open file limit > FD_SETSIZE; limiting max. # of open files to FD_SETSIZE
Maximum connect burst length: 1

Total: connections 10000 requests 10000 replies 10000 test-duration 66.538 s

Connection rate: 150.3 conn/s (6.7 ms/conn, <=1 concurrent connections)
Connection time [ms]: min 4.8 avg 6.6 max 24.6 median 6.5 stddev 1.4
Connection time [ms]: connect 5.2
Connection length [replies/conn]: 1.000

Request rate: 150.3 req/s (6.7 ms/req)
Request size [B]: 62.0

Reply rate [replies/s]: min 141.2 avg 150.1 max 162.2 stddev 6.3 (13 samples)
Reply time [ms]: response 1.3 transfer 0.0
Reply size [B]: header 172.0 content 18605.0 footer 0.0 (total 18777.0)
Reply status: 1xx=0 2xx=10000 3xx=0 4xx=0 5xx=0

CPU time [s]: user 25.99 system 40.27 (user 39.1% system 60.5% total 99.6%)
Net I/O: 2764.9 KB/s (22.7*10^6 bps)

Errors: total 0 client-timo 0 socket-timo 0 connrefused 0 connreset 0
Errors: fd-unavail 0 addrunavail 0 ftab-full 0 other 0
@jmervine
Copy link
Author

I feel the need to note that I may rerun these tests. When running similar tests with grip compression I got drastically different results. So much so that it makes me suspect these results.

@wamatt
Copy link

wamatt commented Apr 19, 2014

Nice one Joshua. Would have been even more helpful to have conducted tests using SPDY connections.*

httperf as you're probably aware uses HTTP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment