I was going through some benchmark pages I noticed that on the the-benchmarker that two javascript libraries nanoexpress & sifrr out-perform fasthttp by 30%.
Both libraries are using the uWebSockets.js package that contains pre-compiled binaries written in c/c++.
wrk -t1 -c400 -d10s http://127.0.0.1:8080/
uWebsocketjs
// Thread Stats Avg Stdev Max +/- Stdev
// Latency 1.17ms 1.95ms 50.30ms 99.44%
// Req/Sec 195.66k 11.91k 203.75k 99.00%
var uws = require('./uws/uws.js');
var app = uws.App()
app.get('/*', (res, req) => {
res.end('Hello World!');
})
app.listen(8080, () => {});
fasthttp
// Thread Stats Avg Stdev Max +/- Stdev
// Latency 1.70ms 496.02us 6.39ms 64.38%
// Req/Sec 120.16k 8.92k 130.69k 77.00%
package main
import "github.com/valyala/fasthttp"
func main() {
fasthttp.ListenAndServe(":8080", func(ctx *fasthttp.RequestCtx) {
ctx.Response.SetBodyString("Hello, World!")
})
}
The main reason I switched from node to go is performance regarding networking, but after seeing this I'm a bit confused in how this actually works.
Or better, is it possible to beat such performance in the future with fasthttp ( re-write/go-update/tricks )
I'm interested in any thoughts regarding this topic :+1:
Actually most of us who seen The Web Framework Benchmark on GitHub knew it, it鈥檚 only useful for routes level, there are many bottleneck where Go can appear to be more performant and where Nodejs fell short: encryption, json, logging, etc.
If Go is designed for your use case then it make sense. :)
There might better performance in the future. Go 1.14 (which will be released next month) already has some improvements. fasthttp itself can't be that much faster, it already does the bare minimum.
The main issue is that Go support proper concurrency which brings some overhead. This overhead is very visible in simple benchmarks like this that don't do anything.
You can see the impact of this proper concurrency when you do something more meaningful inside the request handler. Lets for example calculate 10 MD5 hashes (which is super fast) to simulate some processing that might happen:
wrk -t1 -c400 -d10s http://127.0.0.1:8080/
uWebsocketjs
// Thread Stats Avg Stdev Max +/- Stdev
// Latency 9.36ms 3.30ms 48.12ms 67.27%
// Req/Sec 43.02k 2.47k 47.12k 74.00%
const crypto = require('crypto');
const uws = require('uWebSockets.js');
var app = uws.App()
app.get('/*', (res, req) => {
for (let i = 0; i < 10; i++) {
const h = crypto.createHash('md5').update('foobar').digest('hex');
if (h !== '3858f62230ac3c915f300c664312c63f') {
throw h;
}
}
res.end('Hello World!');
})
app.listen(8080, () => {});
fasthttp
// Thread Stats Avg Stdev Max +/- Stdev
// Latency 2.82ms 363.98us 6.02ms 84.98%
// Req/Sec 140.72k 5.03k 148.43k 75.00%
package main
import (
"crypto/md5"
"encoding/hex"
"github.com/valyala/fasthttp"
)
func main() {
fasthttp.ListenAndServe(":8080", func(ctx *fasthttp.RequestCtx) {
for i := 0; i < 10; i++ {
b := md5.Sum([]byte("foobar"))
h := hex.EncodeToString(b[:])
if h != "3858f62230ac3c915f300c664312c63f" {
panic(h)
}
}
ctx.Response.SetBodyString("Hello, World!")
})
}
@erikdubbelboer Thanks for your example!
Most helpful comment
There might better performance in the future. Go 1.14 (which will be released next month) already has some improvements. fasthttp itself can't be that much faster, it already does the bare minimum.
The main issue is that Go support proper concurrency which brings some overhead. This overhead is very visible in simple benchmarks like this that don't do anything.
You can see the impact of this proper concurrency when you do something more meaningful inside the request handler. Lets for example calculate 10 MD5 hashes (which is super fast) to simulate some processing that might happen:
uWebsocketjs
fasthttp