Skip to content

Instantly share code, notes, and snippets.

@yosssi
Last active Jul 23, 2022
Embed
What would you like to do?
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
@dalovar
Copy link

dalovar 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

correiaa commented Jun 25, 2021

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