Glenn Engstrand

In my last blog, I compared Clojure to Scala when it came to coding micro-services. In this blog, I compare those same micro-services in terms of performance under load in AWS.

Here are some answers to questions about the document below. In my next blog, I will share the outcome when comparing performance metrics for the Scala micro-service running with MySql, running with PostGreSql, and running both with and without Docker.

Q: This blog covers how two implementations of a news feed service compare in terms of performance. Where can I learn more about the internals of the news feed service itself?
A: See Building a Scalable News Feed Web Service in Clojure for a blog on the Clojure version. See Micro-Services: Clojure vs Scala for some coverage on the Scala version. See clojure-news-feed for the source code to both. See my Docker Hub page for some pre-built docker images for both.
Q: What is the fan out for the social broadcast on that load test application?
A: From 2 to 4.
Q: You chose the open source technology Spray as the web container then moved to Finatra when Spray did not scale. Why didn't you choose the Play framework which is more popular than Spray?
A: I looked at Play. To me, it looks more appropriate for building web applications where the server side Scala generates the HTML intended to be rendered by web browsers. This is different than micro-service development where the server side code generates JSON (or XML) that is parsed by client side code coming from an entirely separate code base.
Q: From the document below, it looks like Clojure is the winner. Does this mean that you would always recommend Clojure over Scala?
A: That all depends. Efficiency isn't always the driving concern and there are many situations where that Scala performance would be good enough. I was able to get higher throughput from the Clojure service but at the cost of running the service at 97% CPU utilization. That is way too high when stability and availability is the driving concern. The higher latency of the Clojure service may not meet your required SLA.
Q: What software did you use in your analysis?
A: I used Apache Zeppelin for the throughput and latency and Visual VM for the JVM profiling.
Q: You mentioned learning about Ring in an O'Reilly book on Clojure. Which book is that?
A: Clojure Programming Practical Lisp for the Java World
Q: For the Finatra web service, you schedule the I/O bound tasks in a separate thread pool but then you wait for the tasks to complete before returning the result. Doesn't that defeat the purpose of the thread pool?
A: The Finatra documentation says that controllers can return either the response or a Future of the response. When the code returns the Future, the response is just a promise ID and not the expected serialized JSON. Here is an example. Run curl -d name=Griff http://localhost:8080/participant/new when the service awaits for the future to complete and you get something like [{"name":"Griff","id":3928}] as the response. Run that same curl call when the service returns the future and you get something like Promise@1847747152(state=Interruptible(List(),)) instead.
Q: I thought that Jetty started using NIO so doesn't mean that Jetty no longer requires thread affinity per request?
A: Jetty does use NIO now but Jetty is a servlet container and the servlet API requires a dedicated thread per request. Don't get me wrong. I now believe that thread affinity is a good thing.
Q: Isn't there anything you can do to get the scala news feed to perform better?
A: Sure. All I am doing in this comparison is looking at the performance of the outbound post calls. If I remove the Await.result(f) line from the handler for the outbound post (because the load test application doesn't depend on the response of that operation) and use only one test machine (because there appears to be retrograde scalability in the Scala feed), then you get comparable throughput with the Clojure service at about a third of the latency. Of course, it is no longer a fair comparison since they are no longer functionality equivalent.
Q: You cover the MySql performance but not the Cassandra or Redis performance. Why?
A: In all tests, the Cassandra and Redis performance was awesome and in no way indicative of overall performance problems. For Cassandra, read latency was under 0.2 ms and write latency was an order of magnitude less. Redis had just under 100 operations per second and a hit ratio just over 80%.

Scala vs Clojure: Performance Under Load