The static file server benchmark

Mayank Choubey
Tech Tonic
Published in
3 min readFeb 19, 2024

--

In this article, I will benchmark the performance of static file servers written in various languages: Node.js, Deno, Bun, Python, .NET (ASP.NET Core), Go, Rust, and Java (Spring Boot WebFlux and Quarkus). All languages except Bun will use their out-of-the-box solutions.

The choice of frameworks for each language is based on factors like maturity, stability, and popularity.

Let’s get started!

Test setup

Environment

All tests are executed on MacBook M2 with 16G RAM & 8+4 cores.

Tool

The load tester is a modified version of Bombardier that sends a different request URL for each request (http://localhost:3000/static/<file-name>).

Versions

The software versions are:

  • Node.js 21.6.2
  • Bun 1.0.27
  • Deno 1.40.5
  • Python 3.11.6
  • Go 1.22.0
  • Rust 1.76.0
  • Dotnet 8
  • Java v21 (SB 3.2.2, Quarkus 3.7.2)

Test data

The test data consists of 100K files, with each file 10K in size.

~/Work/source/perfComparisons: ls -l static | wc -l 
100000

~/Work/source/perfComparisons: ls -l static/1
-rw-r--r-- 1 mayankc staff 102400 Jun 23 2023 static/1

~/Work/source/perfComparisons: ls -l static/50000
-rw-r--r-- 1 mayankc staff 102400 Jun 23 2023 static/50000

All files are numbered from 1 to 100000.

Code

The application code in each language is shown below. The decision to choose a framework is again based on maturity and popularity.

With the exception of Bun, where the Elysia static server often fails, all other languages are configured to use the out-of-the-box solution. In some cases, like Java, this only requires configuration.

For Bun, I have written a very basic file server. However, it naturally cannot compete with the advanced capabilities offered by out-of-the-box solutions.

For Rust, the application has been built in release mode.

Results

Each test uses 50 concurrent connections to execute 1M requests. The modified Bombardier test tool generates new static URL for each request. The URL ranges from http://localhost:3000/static/1 to http://localhost:3000/static/100000.

The results in chart form are as follows.

Time Taken & RPS

Latencies

Resource usage

Verdict

The front-runners turned out to be Quarkus, Webflux, and Rust. Now, there are pros and cons of each. The winner is:

  • Rust: Lesser performance, high CPU usage, and minimal memory
  • SpringBoot Webflux: Medium performance, lesser CPU usage, and high memory
  • Quarkus: Maximum performance, lesser CPU usage, and medium to high memory

In short, if resource is not a priority, Quarkus is the winner. If resource is top priority, Rust is the winner.

How about the others? Python, Deno, and Bun has performed the worst. Dotnet is reasonably good, slightly better than Go (Gin).

If there is one winner to be chosen, that would be (my pick):

Overall winner: Quarkus

Thanks for reading this article!

--

--