Benchmarked: The state of Rust web frameworks in 2021
I benchmarked wrong, and these benchmarks are misleading, as my custom bencher bottlenecked. I will update this article with better benchmarks later
There's many web frameworks for Rust. actix-web, warp, rocket, oh my! They all have their distinct ups and downs, but usually actix-web is known as the fastest (albeit not without controversy), and rocket as one of the more user-friendly frameworks.
There's been various benchmarks throughout the years, but how do they all stand in 2021, with tokio 1.0 out?
Today, we're going to be testing 3 separate web frameworks. This is nowhere near all of them, but these are likely the most popular ones, and also ones I know enough about to try to avoid inexperience bias:
- actix-web master, commit 1c95fc2
- warp master, commit ffefea0
- rocket 0.5 master, commit c24f15c
The reason these are all master is that the latest versions with Tokio 1.0 support have not been released fully yet.
In addition, we're going to try to maximize optimization during these rounds: We're going to use snmalloc as our global allocator, to try to minimize allocator overhead, and turning on optimization parameters in Cargo.toml
[profile.release]
opt-level = 3
codegen-units = 1
lto = true
[profile.release.package.'*']
opt-level = 3
codegen-units = 1
The Setup
Here's the various benchmarks we're going to run:
- "Hello World" GET request (just returns a static string)
- JSON GET request (returns JSON containing many different types)
- JSON POST number sorting (POSTs a JSON-serialized array of numbers, and returns a sorted array)
- JSON complex POST request (POSTs a rather complex JSON object, and returns one of the things from it)
Our "complex" JSON object is this mouthful of a type:
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExampleReturn {
pub a: String,
pub b: u32,
pub c: u64,
pub d: f32,
pub e: f64,
pub f: Vec<u64>,
pub g: Vec<f64>,
pub h: Vec<String>,
pub j: BTreeMap<String, u64>,
}
Relevant system info:
- Intel Core i7 8086k, overclocked to 5.1 Ghz
- 32GB DDR4 RAM
- The tests were run inside of Arch Linux in WSL2, running the Linux
5.10.7-111-tkg-upds
kernel. - rustc 1.49.0 (
e1884a8e3
2020-12-29)
The source code for these benchmarks are on my Github, licensed under the BSD-3-Clause license.
There's not much more to explain, so let's get to the point (and probably the only reason you're reading this), the results!
The Results
GET /hello
requests/second | average time | min time | max time | |
---|---|---|---|---|
actix-web | 8415.98 | 118µs | 66µs | 15ms |
rocket | 8230.11 | 121µs | 67µs | 8ms |
warp | 8293.88 | 120µs | 60µs | 15ms |
GET /json
requests/second | average time | min time | max time | |
---|---|---|---|---|
actix-web | 8481.12 | 117µs | 66µs | 12ms |
rocket | 8563.68 | 116µs | 67µs | 12ms |
warp | 8671.42 | 114µs | 67µs | 5ms |
POST /json-sort
requests/second | average time | min time | max time | |
---|---|---|---|---|
actix-web | 7333.80 | 136µs | 78µs | 14ms |
rocket | 7597.79 | 131µs | 75µs | 11ms |
warp | 7640.58 | 130µs | 75µs | 10ms |
POST /json-complex
requests/second | average time | min time | max time | |
---|---|---|---|---|
actix-web | 7471.30 | 133µs | 71µs | 13ms |
rocket | 7802.98 | 127µs | 72µs | 12ms |
warp | 7576.59 | 130µs | 73µs | 13ms |
Latency
average request latency | max request latency | |
---|---|---|
actix-web | 55µs | 6ms |
rocket | 57µs | 7ms |
warp | 52µs | 2ms |
min request latency is not here due to the fact it was broken
average response latency | min response latency | max response latency | |
---|---|---|---|
actix-web | 68µs | 21µs | 4ms |
rocket | 70µs | 25µs | 10ms |
warp | 63µs | 26µs | 3ms |
average round-trip latency | min round-trip latency | max round-trip latency | |
---|---|---|---|
actix-web | 124µs | 62µs | 7ms |
rocket | 128µs | 60µs | 11ms |
warp | 116µs | 69µs | 4ms |