Tuesday, January 28, 2014

Node vs. Java - Web Service Performance


I recently did some comparative testing of web service implementations for a simple in-memory cache. I built functionally equivalent interfaces in Java (REST + SOAP) and Node.js (REST only) for the cache.  As expected, the Node implementation outperformed the Java variants significantly (>100% faster response times).

Cache Implementation

Figure 1 depicts the high-level structure of this cache application.  The cache supports inserts, fetches, and deletes of key/value pairs.
Figure 1
Figure 2 depicts a bit more detail on the physical layout of the application.

In the cases of the REST variants for Java and Node, cache operations are implemented as HTTP verbs (Insert = PUT, Fetch = GET, Remove = DELETE).  Stale entries are cleared from the cache using timeouts with Node and scheduled threads in Java.  Additionally, cache redundancy (loose coherence) is supported simply by utilizing REST calls between the server peers (PUT's and DELETE's).

For the Java SOAP variant, cache ops are implemented with the typical HTTP POST of SOAP envelopes.

Figure 2
Application Organization

Figure 3 below depicts the organization of the Java REST variant of the cache.  Apache Tomcat + Jersey (servlet) are leveraged.

Figure 3

Figure 4 below depicts the organization of the Java SOAP variant of the cache app.  Tomcat + Apache Axis2(servlet) are leveraged.

Figure 4

Figure 5 below depicts the Node.js implementation.  A single worker process is utilized.

Figure 5
Figure 6 depicts the test environment I used.

Java + Node REST Cache Insert Test
ab -A username:password -u restput.txt -n 1000 -c 1 https://server/ctispan/rest/key/111 > results.txt


Java SOAP Cache Fetch Test (I used TCP/IP Monitor in Eclipse to figure out the SOAP formats for ab)
ab -A client:password -T "application/soap+xml; charset=UTF-8" -p soapget.xml -n 1000 -c 1 https://server/ctispan/services/CacheProxyWS.CacheProxyWSHttpSoap11Endpoint/ > results.txt

<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"><soapenv:Body><ns1:getValue xmlns:ns1="http://server.ctispan.jwisoft.com"><ns1:key>111</ns1:key></ns1:getValue></soapenv:Body></soapenv:Envelope>

Java SOAP Cache Insert Test
ab -A client:password -T "application/soap+xml; charset=UTF-8" -p soapput.xml -n 1000 -c 1 https://server/ctispan/services/CacheProxyWS.CacheProxyWSHttpSoap11Endpoint/ > results.txt

<?xml version='1.0' encoding='UTF-8'?><soapenv:Envelope xmlns:soapenv="http://www.w3.org/2003/05/soap-envelope"><soapenv:Body><ns1:putValue xmlns:ns1="http://server.ctispan.jwisoft.com"><ns1:key>111</ns1:key><ns1:value>text111</ns1:value></ns1:putValue></soapenv:Body></soapenv:Envelope>

Below are some graphs of the numbers ab produced.  I wasn't really surprised by the Node vs. Java results.  The Java REST vs. SOAP numbers were a little surprising.  I expected a wide margin between Java REST and SOAP (in REST's favor) due to the overhead of SOAP.  All I can surmise is the Apache Axis2 API is significantly more efficient than the Jersey API.