Vincent Toms

iOS programmer living in Boston MA.

Playing With Node.js

Node.js is a cool little tool for creating web services with high throughput. The idea from what I can gather is you do little bits of processing with the javascript language, typically you listen on a socket and respond. This works as long as your scripts do small things. I have read a fair number of discussions where you can easily break this by doing intense processing etc and kill the whole things, but if you get to that point then node is probably not the right solution.

In the past I would just write an apache module in C that would push back data quickly with out a full stack, but frankly that is a lot of coding and adds a lot of overhead that can be bypassed.

As you can see below from my AB run node is fast. The first output is from hitting my node.js code, the second a static page request to nginx. Some of this speed difference could be due to the fact we’re passing more data back in the static page but I didn’t have time to do an apples to apples comparison here to be sure.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
$ ab -n 10000 -c 100 http://10.77.77.2:8080/
...
...
Concurrency Level:      100
Time taken for tests:   9.293587 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      2050000 bytes
HTML transferred:       980000 bytes
Requests per second:    1076.01 [#/sec] (mean)
Time per request:       92.936 [ms] (mean)
Time per request:       0.929 [ms] (mean, across all concurrent requests)
Transfer rate:          215.31 [Kbytes/sec] received

$ ab -n 10000 -c 100 http://10.77.77.2/
...
...
Concurrency Level:      100
Time taken for tests:   14.793172 seconds
Complete requests:      10000
Failed requests:        0
Write errors:           0
Total transferred:      199140000 bytes
HTML transferred:       197020000 bytes
Requests per second:    675.99 [#/sec] (mean)
Time per request:       147.932 [ms] (mean)
Time per request:       1.479 [ms] (mean, across all concurrent requests)
Transfer rate:          13146.07 [Kbytes/sec] received

Below is a message that comes out of band from my Node.js service.

 

This is the code I use to query my service.

Load jQuery and call my node.js service
1
2
3
4
5
6
7
8
9
10
11
<script src="http://code.jquery.com/jquery-latest.js"></script>
<script>
  jQuery.noConflict();
  jQuery(document).ready(function(){
  
    jQuery.getJSON("http://vincenttoms.com:8080", "jsoncallback=?",
        function(json){
          jQuery("#holder").html(json.str);
        });
  });
</script>

This is the code for my Node.js service this is a trivial example. My guess is there is a better more codey way to write out the JSON data.

(nodeserver.js) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// load in http and url libraries
var http = require('http');
var url = require('url');

// start up a server listening on all IP's on port 8080
http.createServer(
  function (req, res) {
      // get the date
      var now = new Date();
      
      // send back a 200 and the content type
      res.writeHead(200, {'Content-Type': 'application/json'});
      
      // build my JSON string by hand would like to do this all code but not sure at the moment  
      var output = "{\"str\":\"Hello from my Node.js server today is " + now.toString("dddd, mmmm dS, yyyy, h:MM:ss TT")+"\"}";
      
      // parse the url query
      var url_parts = url.parse(req.url, true);
      var query = url_parts.query;

      // write the response
      res.end(query.jsoncallback+"("+output+")");
}).listen(8080, '0.0.0.0');

// log out something to the console
console.log('Server running at http://0.0.0.0:8080/');

It was puking when trying to parse the JSON and some googling lead me to this as the solution.

Ugly hack
1
res.end(query.jsoncallback+"("+output+")");

Then to have your node service running all the time you use the nohup command.

Ugly hack
1
$ nohup node nodeserver.js > outfile.log &

I suspect there is probably a much cleaner way to implement this so any thoughts would be greatly appreciated.

Comments