First off, forget about Apache. Apache is slow.
I was intrigued by the question so I decided to write the smallest possible webserver I could come up with in Go, which is read the request, ignore it, and respond with HTTP/1.1 200 OK
. Note that this breaks the HTTP spec because it doesn’t return any Date
headers or anything, but I assume that’s not really a problem? Less headers = less bytes over the wire = less time.
So here is the code
package main
import (
"io"
"log"
"net"
"os"
"runtime"
)
func handleConnection(conn net.Conn) {
defer conn.Close()
b := make([]byte, 100)
for {
_, err := conn.Read(b)
if err == io.EOF {
return
}
if containsDoubleLnRf(b) {
break
}
}
conn.Write([]byte("HTTP/1.1 200 OK\n"))
}
func containsDoubleLnRf(b []byte) bool {
for i := 0; i < len(b)-3; i++ {
if b[i] == 13 && b[i+1] == 10 && b[i+2] == 13 && b[i+3] == 10 {
return true
}
}
return false
}
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
ln, err := net.Listen("tcp", ":8080")
if err != nil {
log.Printf("Error starting server: %s", err)
os.Exit(1)
}
for {
conn, err := ln.Accept()
if err != nil {
log.Printf("Could not accept connection: %s", err)
continue
}
go handleConnection(conn)
}
}
I have benchmarked this using ab -n 100000 -c 100
and got:
Concurrency Level: 100
Time taken for tests: 17.481 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 1600000 bytes
HTML transferred: 0 bytes
Requests per second: 5720.57 [#/sec] (mean)
Time per request: 17.481 [ms] (mean)
Time per request: 0.175 [ms] (mean, across all concurrent requests)
Transfer rate: 89.38 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 8 2.0 8 40
Processing: 1 9 2.5 9 44
Waiting: 0 7 2.4 6 41
Total: 6 17 2.3 17 50
The same thing for NGiNX serving a blank html file yielded:
Concurrency Level: 100
Time taken for tests: 21.586 seconds
Complete requests: 100000
Failed requests: 0
Write errors: 0
Total transferred: 15600000 bytes
HTML transferred: 0 bytes
Requests per second: 4632.73 [#/sec] (mean)
Time per request: 21.586 [ms] (mean)
Time per request: 0.216 [ms] (mean, across all concurrent requests)
Transfer rate: 705.77 [Kbytes/sec] received
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 9 7.9 8 229
Processing: 2 12 13.1 10 231
Waiting: 1 9 11.3 7 221
Total: 14 22 15.6 18 241
so basically my go program is about 23% faster than NGiNX
(to run the program, install go, save my code to a file, say server.go
, when in the directory where server.go
is stored, type go build server.go
and then ./server
)