Skip to content

Instantly share code, notes, and snippets.

@yosssi
Last active August 7, 2024 20:10
Show Gist options
  • Save yosssi/4d719cccdf185259ea1d to your computer and use it in GitHub Desktop.
Save yosssi/4d719cccdf185259ea1d to your computer and use it in GitHub Desktop.
Go networking performance vs Nginx

1. Nginx

$ wrk -t12 -c400 -d2s http://127.0.0.1:8080
Running 2s test @ http://127.0.0.1:8080
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     7.71ms    3.16ms  23.05ms   69.17%
    Req/Sec     3.44k     1.98k    7.80k    58.22%
  63697 requests in 2.00s, 17.86MB read
  Socket errors: connect 155, read 47, write 0, timeout 66
Requests/sec:  31780.82
Transfer/sec:      8.91MB

2. Go with an empty response

main.go

package main

import (
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

	})
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
$ GOMAXPROCS=2 go run main.go
$ wrk -t12 -c400 -d2s http://127.0.0.1:8080
Running 2s test @ http://127.0.0.1:8080
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.79ms  492.55us   7.85ms   76.02%
    Req/Sec     6.63k     2.47k   13.10k    60.47%
  124846 requests in 2.00s, 13.81MB read
  Socket errors: connect 155, read 50, write 0, timeout 66
Requests/sec:  62314.54
Transfer/sec:      6.89MB

3. Go with a simple response

main.go

package main

import (
	"fmt"
	"log"
	"net/http"
)

func main() {
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprint(w, "Hello")
	})
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
$ GOMAXPROCS=2 go run main.go
$ wrk -t12 -c400 -d2s http://127.0.0.1:8080
Running 2s test @ http://127.0.0.1:8080
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.79ms  492.55us   7.85ms   76.02%
    Req/Sec     6.63k     2.47k   13.10k    60.47%
  124846 requests in 2.00s, 13.81MB read
  Socket errors: connect 155, read 50, write 0, timeout 66
Requests/sec:  62314.54
Transfer/sec:      6.89MB
mac:~ yoshidakeiji$ wrk -t12 -c400 -d2s http://127.0.0.1:8080
Running 2s test @ http://127.0.0.1:8080
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     3.87ms  725.83us  13.10ms   84.56%
    Req/Sec     6.50k     3.06k   23.70k    60.89%
  121878 requests in 2.00s, 14.06MB read
  Socket errors: connect 155, read 54, write 0, timeout 66
Requests/sec:  60837.67
Transfer/sec:      7.02MB

4. Go with a file server

main.go

package main

import (
	"log"
	"net/http"
)

func main() {
	http.Handle("/", http.FileServer(http.Dir("/Users/yoshidakeiji/www")))
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
$ GOMAXPROCS=2 go run main.go
$ wrk -t12 -c400 -d2s http://127.0.0.1:8080
Running 2s test @ http://127.0.0.1:8080
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    14.86ms    1.52ms  19.52ms   74.31%
    Req/Sec     1.65k   795.40     2.53k    69.16%
  32254 requests in 2.00s, 7.47MB read
  Socket errors: connect 155, read 0, write 0, timeout 66
Requests/sec:  16088.43
Transfer/sec:      3.73MB

5. Go with a cached file server

main.go

package main

import (
	"log"
	"net/http"

	"github.com/yosssi/go-fileserver"
)

func main() {
	fs := fileserver.New(fileserver.Options{})
	http.Handle("/", fs.Serve(http.Dir("/Users/yoshidakeiji/www")))
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
$ GOMAXPROCS=2 go run main.go
$ wrk -t12 -c400 -d2s http://127.0.0.1:8080
Running 2s test @ http://127.0.0.1:8080
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency    13.55ms    2.76ms  27.83ms   75.61%
    Req/Sec     2.19k   393.78     3.04k    57.03%
  51146 requests in 2.00s, 8.93MB read
  Socket errors: connect 0, read 190, write 0, timeout 0
Requests/sec:  25581.43
Transfer/sec:      4.46MB

6. Go with a cached file server which calls io.Copy instead of http.ServeContent

main.go

package main

import (
	"log"
	"net/http"

	"github.com/yosssi/go-fileserver"
)

func main() {
	fs := fileserver.New(fileserver.Options{})
	http.Handle("/", fs.Serve(http.Dir("/Users/yoshidakeiji/www")))
	if err := http.ListenAndServe(":8080", nil); err != nil {
		log.Fatal("ListenAndServe: ", err)
	}
}
$ GOMAXPROCS=2 go run main.go
$ wrk -t12 -c400 -d2s http://127.0.0.1:8080
Running 2s test @ http://127.0.0.1:8080
  12 threads and 400 connections
  Thread Stats   Avg      Stdev     Max   +/- Stdev
    Latency     5.01ms  641.48us   9.39ms   79.67%
    Req/Sec     5.27k     1.48k    9.30k    60.07%
  118962 requests in 2.00s, 13.17MB read
  Socket errors: connect 0, read 125, write 0, timeout 0
Requests/sec:  59517.07
Transfer/sec:      6.59MB
Copy link

ghost commented Feb 15, 2018

Those results are pretty impressive. Tempts me to run both my frontend and backend using the same Go server just to simplify deployment and reduce running processes. I know its not really a huge margin, but for what I am doing this may just make sense.

@ChandraNarreddy
Copy link

This is quite impressive. What is NGINX version and configuration, is it serving static content?

@larytet
Copy link

larytet commented Jun 7, 2018

In my tests switch to fasthttp gives x1.5 to x2 boost

Copy link

ghost commented Nov 23, 2018

@nixtoshi
Copy link

nixtoshi commented Nov 24, 2018

see https://github.com/tidwall/evio

Interesting. Is evio faster than nginx and production ready? Does it have any built-in protection against DDoS attacks like nginx

Great contribution

@correiaa
Copy link

I'll update everyone here. I am about to give this a GO :). I am at my limit with Nginx and will be building my apps Rest api with this. Interested to see how hard it can get hit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment