title: UDP send performance in Node.js
body: <p>I am benchmarking a Java UDP client that continuously sends datagrams with a payload of 100 bytes as fast as it can. It was implemented using <code>java.nio.*</code>. Tests show that it's able to achieve a steady throughput of <strong>220k datagrams per second</strong>. I am not testing with a server; the client just sends the datagrams to some unused port on <em>localhost</em>.</p>
  
  <p>I decided to run the same test in Node.js to compare both technologies and it was surprisingly sad to see that <strong>Node.js performed 10 times slower than Java</strong>. Let me walk you through my code.</p>
  
  <p>First, I create a UDP socket using Node.js's <a href="https://nodejs.org/api/dgram.html" rel="nofollow noreferrer">dgram module</a>:</p>
  
  <pre><code>var client = require('dgram').createSocket("udp4");
  </code></pre>
  
  <p>Then I create a function that sends a datagram using that socket:</p>
  
  <pre><code>function sendOne() {
      client.send(message, 0, message.length, SERVER_PORT, SERVER_ADDRESS, onSend);
  }
  </code></pre>
  
  <p>The variable <code>message</code> is a buffer created from a string with a hundred characters when the application starts:</p>
  
  <pre><code>var message = new Buffer(/* string with 100 chars */);
  </code></pre>
  
  <p>The function <code>onSend</code> just increments a variable that holds how many datagrams were sent so far. Next I have a function that constantly calls <code>sendOne()</code> using <a href="https://nodejs.org/api/timers.html#timers_setimmediate_callback_arg" rel="nofollow noreferrer"><code>setImmediate()</code></a>:</p>
  
  <pre><code>function sendForever() {
      sendOne();
      setImmediate(sendForever);
  } 
  </code></pre>
  
  <p>Initially I tried to use <code>process.nextTick(sendForever)</code> but I found out that it always puts itself at the tip of the event queue, even before IO events, as the docs <a href="https://nodejs.org/api/process.html#process_process_nexttick_callback" rel="nofollow noreferrer">says</a>:</p>
  
  <blockquote>
    <p>It runs before any additional I/O events (including timers) fire in subsequent ticks of the event loop.</p>
  </blockquote>
  
  <p>This prevents the <em>send</em> IO events from ever happening, as <code>nextTick</code> is constantly putting <code>sendForever</code> at the tip of the queue at every tick. The queue grows with unread IO events until it makes Node.js crash:</p>
  
  <pre><code>fish: Job 1, 'node client' terminated by signal SIGSEGV (Address boundary error)
  </code></pre>
  
  <p>On the other hand, <code>setImmediate</code> fires after I/O events callbacks, so that's why I'm using it.</p>
  
  <p>I also create a timer that once every 1 second prints to the console how many datagrams were sent in the last second:</p>
  
  <pre><code>setInterval(printStats, 1000);
  </code></pre>
  
  <p>And finally I start sending:</p>
  
  <pre><code>sendForever();
  </code></pre>
  
  <p>Running on the same machine as the Java tests ran, Node.js achieved a steady throughput of <strong>21k datagrams per second, ten times slower than Java</strong>.</p>
  
  <p>My first guess was to put two <code>sendOne</code>'s for every tick to see if it would double the throughput:</p>
  
  <pre><code>function sendForever() {
      send();
      send();  // second send
      setImmediate(sendForever);
  }
  </code></pre>
  
  <p>But it didn't change the throughput whatsoever.</p>
  
  <p>I have a repository available on GitHub with the complete code:</p>
  
  <p><a href="https://github.com/luciopaiva/udp-perf-js" rel="nofollow noreferrer">https://github.com/luciopaiva/udp-perf-js</a></p>
  
  <p>Simply clone it to your machine, <code>cd</code> into the folder and run:</p>
  
  <pre><code>node client
  </code></pre>
  
  <p>I want to open a discussion about how this test could be improved in Node.js and if there's some way we can increase Node.js's throughput. Any ideas?</p>
  
  <p><em>P.S.: for those interested, here is the <a href="https://github.com/luciopaiva/udp-perf-java" rel="nofollow noreferrer">Java part</a>.</em></p>