Table of Contents
Scope
The idea behind this repository is to benchmark different languages implementation of HTTP server.
Hello World
The application i tested is minimal: the HTTP version of the Hello World example.
This approach allows including languages i barely know, since it is pretty easy to find such implementation online.
If you're looking for more complex examples, you will have better luck with the TechEmpower benchmarks.
Disclaimer
Please do take the following numbers with a grain of salt: it is not my intention to promote one language over another basing on micro-benchmarks.
Indeed you should never pick a language just basing on its presumed performance.
Languages
I have filtered the languages by single runtime (i.e. Java on JVM): this way i can focus on a specific stack, keeping it updated to the last available version/APIs. Where possible i just relied on the standard library, but when it is not production-ready (i.e. Ruby, Python) or where the language footprint is deliberately minimal (i.e. Rust).
Ruby
Ruby 2.6.5 is installed via rbenv.
Ruby is a general-purpose, interpreted, dynamic programming language, focused on simplicity and productivity.
Python
Python 3.8.0 is installed via homebrew.
Python is a widely used high-level, general-purpose, interpreted, dynamic programming language.
JavaScript
Node.js version 13.0.1 is installed by official OSX package.
Node.js is based on the V8 JavaScript engine, optimized by Google and supporting most of the new language's features.
Dart
Dart version 2.6.1 is installed via homebrew.
Dart is a VM based, object-oriented, sound typed language using a C-style syntax that transcompiles optionally into JavaScript.
Elixir
Elixir 1.9.1 is installed via homebrew.
Elixir is a purely functional language that runs on the Erlang VM and is strongly influenced by the Ruby syntax.
Java
Java JDK 13.0.0 is installed by official OSX package.
Java is a VM based, statically typed, general-purpose language that is thread safe, object-oriented and, from version 8, supports functional paradigms.
Crystal
Crystal 0.31.1 is installed via homebrew.
Crystal has a syntax very close to Ruby, but brings some desirable features such as statically typing and ahead of time (AOT) compilation.
Nim
Nim 1.0.2 is installed via homebrew.
Nim is an AOT, Python inspired, statically typed language that comes with an ambitious compiler aimed to produce code in C, C++, JavaScript or ObjectiveC.
GO
GO language version 1.13.4 is installed by official OSX package.
GO is an AOT language that focuses on simplicity and offers a broad standard library with CSP constructs built in.
Rust
Rust language version 1.39.0 is installed by official package.
Rust is an AOT, garbage collector free programming language, preventing segfaults and granting thread safety.
Tools
Wrk
I used wrk as the loading tool.
I measured each application server six times, picking the best lap (but for VM based languages demanding longer warm-up).
wrk -t 4 -c 100 -d30s --timeout 2000 http://0.0.0.0:9292
Platform
These benchmarks are recorded on a MacBook PRO 15 mid 2015 having these specs:
- macOS Mojave
- 2.2 GHz Intel Core i7 (4 cores)
- 16 GB 1600 MHz DDR3
RAM and CPU
I measured RAM and CPU consumption by using macOS Activity Monitor dashboard and recording max consumption peak.
For the languages relying on pre-forking parallelism i reported the average consumption by taking a snapshot during the stress period.
Benchmarks
Results
Language | App Server | Requests/sec | RAM (MB) | CPU (%) |
---|---|---|---|---|
Elixir | Plug with Cowboy | 45477.66 | 45.3 | 619.0 |
Dart | Dart HttpServer | 48280.33 | 45.9 | 539.3 |
Ruby | Puma | 56979.27 | > 110 | > 520 |
JavaScript | Node Cluster | 84260.52 | > 150 | > 300 |
Rust | Hyper | 97421.94 | 4.5 | 450.0 |
GO | GO ServeMux | 109945.72 | 7.3 | 441.5 |
Python | Gunicorn with Meinheld | 110583.42 | > 40 | > 380 |
Java | Jetty NIO | 116388.13 | 233.1 | 436.3 |
Nim | httpbeast | 116588.18 | 24.1 | 99.7 |
Crystal | Crystal HTTP | 120141.48 | 8.4 | 282.3 |
Puma
I tested Ruby by using a plain Rack application served by Puma.
Bootstrap
puma -w 8 -t 2 --preload servers/rack_server.ru
Gunicorn with Meinheld
I tested Python by using Gunicorn spawning Meinheld workers with a plain WSGI compliant server.
Bootstrap
cd servers
gunicorn -w 4 -k meinheld.gmeinheld.MeinheldWorker -b :9292 wsgi_server:app
Node Cluster
I used the cluster module included into Node's standard library.
Bootstrap
node servers/node_server.js
Dart HttpServer
I used the async HTTP server embedded into the Dart standard library and compiled it with dart2native
AOT compiler.
Bootstrap
dart2native servers/dart_server.dart -k aot
dartaotruntime servers/dart_server.aot
Plug with Cowboy
I tested Elixir by using Plug library that provides a Cowboy adapter.
Bootstrap
cd servers/plug_server
MIX_ENV=prod mix compile
MIX_ENV=prod mix run --no-halt
Jetty NIO
I tested Java by using Jetty with the non blocking IO (NIO) APIs.
Bootstrap
cd servers/jetty_server
javac -cp jetty-all-uber.jar HelloWorld.java
java -server -cp .:jetty-all-uber.jar HelloWorld
Crystal HTTP
I used Crystal HTTP server standard library, enabling parallelism by using the preview_mt
flag.
Bootstrap
crystal build -Dpreview_mt --release servers/crystal_server.cr
./crystal_server
httpbeast
To test Nim i opted for the httpbeast library: an asynchronous server relying on Nim HTTP standard library.
Bootstrap
nim c -d:release --threads:on servers/httpbeast_server.nim
./servers/httpbeast_server
GO ServeMux
I used the HTTP ServeMux GO standard library.
Bootstrap
go run servers/servemux_server.go
Hyper
I tested Rust by using the Hyper, an HTTP implementation based on Tokio.io.
Bootstrap
cd servers/hyper_server
cargo run --release