Some background
If you’re a developer looking to build a reliable, memory safe, high performance application today, Rust & Go are surely your options.
If you’re looking to get even more performance out of your internal applications, you might also want to look at using gRPC instead of a normal REST api. All these are solutions to reducing your computational overhead.
I try to compare various libraries to understand their performance and hope you find it helpful.
Libraries looked at
- tower-grpc (Rust)
A performant rust library, though it is replaced with tonic - grpc-go (Golang)
The official go module for grpc. - grpc-rust (Rust)
Still in development, another grpc in rust. Looked promising. - tonic (Rust)
An improved update from tower-grpc supporting the new await syntax - grpc-node (NodeJs)
Included for a benchmarking reference point. - grpc-rs (Rust — C bindings)
A rust library that uses grpc
Benchmark Tool
For the benchmark I’ll use the equivalent of Hey for gRPC, ghz.
The test will focus on how much overhead there is if the same load of 10,000 concurrent requests is sent to servers using each of the libraries above. I will use the same helloworld greeter for each. TLS will not be enabled for any of the tests so we can get an idea of the raw performance with each.
grpc-go
Summary:
Count: 10000
Total: 229.40 ms
Slowest: 6.26 ms
Fastest: 0.11 ms
Average: 1.04 ms
Requests/sec: 43591.54Response time histogram:
0.114 [1] |
0.728 [3355] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
1.343 [4580] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
1.957 [1519] |∎∎∎∎∎∎∎∎∎∎∎∎∎
2.572 [294] |∎∎∎
3.187 [36] |
3.801 [11] |
4.416 [74] |∎
5.030 [52] |
5.645 [45] |
6.259 [33] |Latency distribution:
10 % in 0.46 ms
25 % in 0.64 ms
50 % in 0.88 ms
75 % in 1.24 ms
90 % in 1.68 ms
95 % in 2.00 ms
99 % in 4.77 msStatus code distribution:
[OK] 10000 responses
tonic
Summary:
Count: 10000
Total: 581.81 ms
Slowest: 6.39 ms
Fastest: 0.17 ms
Average: 2.84 ms
Requests/sec: 17187.66Response time histogram:
0.174 [1] |
0.796 [5] |
1.418 [6] |
2.040 [167] |∎
2.662 [3427] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
3.284 [5074] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
3.906 [1048] |∎∎∎∎∎∎∎∎
4.528 [217] |∎∎
5.150 [29] |
5.773 [21] |
6.395 [5] |Latency distribution:
10 % in 2.35 ms
25 % in 2.55 ms
50 % in 2.79 ms
75 % in 3.07 ms
90 % in 3.39 ms
95 % in 3.66 ms
99 % in 4.22 msStatus code distribution:
[OK] 10000 responses
grpc-node
Summary:
Count: 10000
Total: 589.25 ms
Slowest: 12.56 ms
Fastest: 1.21 ms
Average: 2.88 ms
Requests/sec: 16970.81Response time histogram:
1.206 [1] |
2.341 [2592] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
3.476 [5516] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
4.612 [1588] |∎∎∎∎∎∎∎∎∎∎∎∎
5.747 [180] |∎
6.882 [42] |
8.017 [32] |
9.152 [5] |
10.288 [20] |
11.423 [6] |
12.558 [18] |Latency distribution:
10 % in 2.14 ms
25 % in 2.33 ms
50 % in 2.62 ms
75 % in 3.24 ms
90 % in 3.85 ms
95 % in 4.26 ms
99 % in 6.41 msStatus code distribution:
[OK] 10000 responses
tower-grpc
Summary:
Count: 10000
Total: 571.88 ms
Slowest: 10.59 ms
Fastest: 0.25 ms
Average: 2.76 ms
Requests/sec: 17486.12Response time histogram:
0.246 [1] |
1.280 [139] |∎
2.314 [2927] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
3.348 [5198] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
4.382 [1390] |∎∎∎∎∎∎∎∎∎∎∎
5.416 [114] |∎
6.450 [61] |
7.484 [80] |∎
8.518 [47] |
9.552 [31] |
10.586 [12] |Latency distribution:
10 % in 1.80 ms
25 % in 2.20 ms
50 % in 2.65 ms
75 % in 3.13 ms
90 % in 3.64 ms
95 % in 4.05 ms
99 % in 7.18 msStatus code distribution:
[OK] 10000 responses
grpc-rust
Summary:
Count: 10000
Total: 479.30 ms
Slowest: 8.15 ms
Fastest: 0.90 ms
Average: 2.34 ms
Requests/sec: 20863.64Response time histogram:
0.901 [1] |
1.626 [193] |∎
2.351 [5587] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
3.076 [3562] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
3.801 [506] |∎∎∎∎
4.526 [119] |∎
5.251 [16] |
5.976 [5] |
6.701 [2] |
7.426 [2] |
8.151 [7] |Latency distribution:
10 % in 1.87 ms
25 % in 2.03 ms
50 % in 2.25 ms
75 % in 2.57 ms
90 % in 2.90 ms
95 % in 3.23 ms
99 % in 4.11 msStatus code distribution:
[OK] 10000 responses
Grpc-rs
Summary:
Count: 10000
Total: 289.82 ms
Slowest: 4.22 ms
Fastest: 0.22 ms
Average: 1.36 ms
Requests/sec: 34504.74Response time histogram:
0.222 [1] |
0.621 [195] |∎∎
1.021 [1829] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
1.420 [4059] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
1.820 [2625] |∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎∎
2.219 [972] |∎∎∎∎∎∎∎∎∎∎
2.618 [239] |∎∎
3.018 [45] |
3.417 [18] |
3.817 [6] |
4.216 [11] |Latency distribution:
10 % in 0.87 ms
25 % in 1.07 ms
50 % in 1.30 ms
75 % in 1.62 ms
90 % in 1.90 ms
95 % in 2.07 ms
99 % in 2.56 msStatus code distribution:
[OK] 10000 responses
Summary
Conclusion
The results indicate rust is on par with node in terms of performance, which was a bit of a shocking result.
The go library was extremely performant, both in concurrency & minimal overhead.
If anyone has some thoughts to why the go library seems to be so performant relatively give me a shout out!
UPDATE: Thanks to Trisfald for suggesting grpc-rs as a (presently) more performant incarnation of gRPC in rust.