Low Memory Ring Adapters

There was a recent reddit question about running Clojure web applications in "low" memory. This piqued my curiosity, how low of memory can Clojure ring servers run under?

I managed to find a reference on GitHub to Jetty running in 15MB of memory on embedded systems, a pretty impressive number!

To measure the effects, I created ring-graph to graph the results of running a simple ring application under different heap sizes. The req/s are measured once started using wrk, with a configurable workload. The ring application itself is the hello world taken from http-kit’s server documentation:

(defn app [req]
  {:status  200
   :headers {"Content-Type" "text/html"}
   :body    "hello HTTP!"})

While this isn’t a measure of realistic workloads, it gives a baseline for what a web server can achieve when we restrict memory. Unfortunately, most applications use some proprietary extensions to ring (e.g. for websockets or streaming files with non-blocking I/O) so in practice swapping different ring servers out is difficult. However, that would make for an interesting future extension (although it may require changing how the benchmark is run to create a more realistic user).

The most common cause of failure below 10M of memory was "ClassNotFoundException", which may point to some other underlying problem that would allow reducing the required memory to start.

Results as Graph

The configuration used for this build is:

  • 2 threads

  • 2 connections

  • 20 second duration

However, I’ve seen the same ratios at almost every configuration I’ve tried. Anywhere you see a missing bar, that indicates that the server failed to start.

As you can see, pohjavirta is the absolute winner here, by a long shot. The only place it starts to fall down is at 10M and below, where http-kit pulls ahead. However, pohjavirta is still WIP, so isn’t necessarily a good measure. http-kit achieves a high performance at all memory sizes and is stable.

Aleph and Immutant start failing at 10M of memory. Undertow joins them at 9M.

Vertx really tanks in performance at 10M. Vertx is another WIP adapter for ring, but I did expect better numbers given Vertx’s overall performance.

In the future, I’d like to compare some more sophisticated applications. In particular, I think it’ll be interesting to see how different servers cope with streaming, e.g. for serving files. I also think comparisons of async vs sync would be interesting.