Saturday, May 12, 2012

First error with node.js

This week I started to read "Node up and running" book, and followed the examples to explore node.js which is really promising for javascript on server side. Installing node, or setup other libraries using NPM is quite easy, and running sample node.js is also trivia. However, my ever first error from node.js is as below
node.js:201
        throw e; // process.nextTick error, or 'error' event on first tick
              ^
Error: listen EADDRINUSE
    at errnoException (net.js:614:11)
    at Array.0 (net.js:704:26)
    at EventEmitter._tickCallback (node.js:192:40)
It is quite understandable from "listen EADDRINUSE", the error means some other process already occupy the address. But I did quit original node process.

Well, did a quick check ps aux | grep node found the previous node process was still there, but I did Ctrl-Z, right? So far I have not realized the root cause, so I went ahead to kill -9 node-PID to get rid of previous node process, and get the updated node.js running.

Why previous quite (Ctrl-Z) didn't work? Quickly checked wikipedia and found the answer
http://en.wikipedia.org/wiki/Signal_%28computing%29

  • Ctrl-C (in older Unixes, DEL) sends an INT signal (SIGINT); by default, this causes the process to terminate.
  • Ctrl-Z sends a TSTP signal (SIGTSTP); by default, this causes the process to suspend execution.
It is clear that I should use Ctrl-C to terminate the node process, or kill the process.

Tuesday, May 8, 2012

Increase initcwnd for TCP Performance

MTU & MSS
MTU (maximum transmission unit): Nearly all IP over Ethernet implementations use the Ethernet V2 frame format, which is 1500 bytes. Linux ifconfig output can show MTU size.

MSS (The maximum segment size)  is a parameter of the TCP protocol that specifies the largest amount of data, specified in octets, that a computer or communications device can receive in a single TCP segment, and therefore in a single IP datagram. It does not count the TCP header or the IP header.

Therefore, TCP/IP Headers + MSS ≤ MTU
MTU = 1500
TCP Header = 20
IP Header = 20
TCP Option = 12 (optional)
MSS = 1460 (1448 if there is TCP Option)

Two TCP Windows
Congestion Window (cwnd) controls the number of packets a TCP flow may have in the network in any given time. cwnd is dynamically adapting to changing network condition. TCP Slow-start is one of the algorithms that TCP uses in its quest to control congestion inside the network and it is also known as the exponential growth phase.When TCP reaches a certain threshold (also known as sstrsesh) it will enter the linear growth, Congestion avoidance. Linux 2.6.39 increased the initial congestion window to 10 packets, previous versions are 3.

The Receiver Advertised Window (rwnd) is the buffer size sent in each ACK from TCP receiver to TCP sender. The window size is 65535 (64K) bytes on Windows/Mac/iOS.

The purpose of sliding window is to prevent from the sender to send too many packets to over flow the network resource or the receiver's buffer. The "sliding window size" is the maximum amount of data we can send without having to wait for ACK.

Therefore, with suggested 10 initcwnd size, sliding window can have 10 * MSS data flowing the network without ACK, it will definitely improve TCP performance, eliminating TCP slow start.

How to Change initcwnd/initrwnd
ip route show
sudo ip route change default via 192.168.1.1 dev eth0 initcwnd 10
ip route show

ip route show
sudo ip route change default via 192.168.1.1 dev eth0 initrwnd 10
ip route show

Notes:
1. The advertised receive window on Linux is called initrwnd. It can only be adjusted on linux kernel 2.6.33 and newer
2. This changes the initcwnd and initrwnd until the next reboot.
3. To persist the changes, try out below script (copied from cdnplanet.com, but not verified)
cp /etc/sysconfig/network-scripts/ifup-post /etc/sysconfig/network-scripts/ifup-post.bak; sed -i -e "/^exit 0/d" /etc/sysconfig/network-scripts/ifup-post; echo "ip route change " $(ip route show | grep '^default' | sed 's/initcwnd [0-9]*//') " initcwnd 10" >> /etc/sysconfig/network-scripts/ifup-post; echo "exit 0" >> /etc/sysconfig/network-scripts/ifup-post

Other Tunings
disable net.ipv4.tcp_slow_start_after_idle
setting tcp_slow_start_after_idle to 0 (for disabling it) to speed up initial connections, otherwise it will cause your keepalive connection to return to slow start after TCP_TIMEOUT_INIT (3 seconds)

disable Nagle algorithm
TCP implementations usually provide applications with an interface to disable the Nagle algorithm. This is typically called the TCP_NODELAY option.

Other options on CentOS
sysctl -w net.core.rmem_max=16777216
sysctl -w net.core.wmem_max=16777216
sysctl -w net.ipv4.tcp_rmem=4096 87380 16777216
sysctl -w net.ipv4.tcp_wmem=4096 87380 16777216
sysctl -w net.core.netdev_max_backlog=30000
sysctl -w net.ipv4.tcp_congestion_control=htcp

Reference
http://kernelnewbies.org/Linux_2_6_39
http://www.cdnplanet.com/blog/tune-tcp-initcwnd-for-optimum-performance/
http://monolight.cc/2010/12/increasing-tcp-initial-congestion-window/
http://www.osischool.com/protocol/Tcp/slidingWindow/index.php

Monday, May 7, 2012

Javascript Logging

Quick Reference
console.log(object[, object, ...])
console.debug(object[, object, ...])
console.info(object[, object, ...])
console.warn(object[, object, ...])
console.error(object[, object, ...])
console.assert(expression[, object, ...])
console.dir(object)
console.dirxml(node)
console.trace()
console.group(object[, object, ...])
console.groupEnd()
console.time(name)
console.timeEnd(name)
console.profile([title])
console.profileEnd()
console.count([title])

Examples
console.log("My name is %s, and I am %d years old", 'Jim', 30);
String Substitution Patterns
%s String
%d, %i Integer (numeric formatting is not yet supported)
%f Floating point number (numeric formatting is not yet supported)
%o Object hyperlink


Cross Browsers
Firefox (Firebug/FireBug Lite)
Chrome
Safari
Opera
IE

Option 1:
window.console||(window.console={log:function(){}});

Option 2:
window.log = function(){
  log.history = log.history || [];   // store logs to an array for reference
  log.history.push(arguments);
  if(this.console){
    if (arguments.length == 1) {
        console.log(arguments[0]);
    }
    else {
        console.log( Array.prototype.slice.call(arguments) );
    }
  }
};

Reference
http://geekswithblogs.net/renso/archive/2009/07/02/firebug-console-quick-reference-guide.aspx
http://getfirebug.com/logging
http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/