I'm writing a simple proxy in go that relays an HTTP request to one or more backend servers. Right now I'm still using only one backend server, but performance is not good and I'm sure I am doing something wrong. Probably related to how I send the HTTP request to another server: if I comment the call to send()
then the server goes blazing fast, yielding more than 14 krps. While with the call to send()
performance drops to less than 1 krps and drops even lower with time. This on a MacBook Pro.
The code is based on trivial code samples; I have created the client
and reused it following the recommendation in the docs. Tests are done with Apache ab
:
$ ab -n 10000 -c 10 -k "http://127.0.0.1:8080/test"
The backend server running on port 55455 does not change between experiments; Apache or nginx can be used. My custom web server yields more than 7 krps when measured directly, without proxy:
$ ab -n 10000 -c 10 -k "http://127.0.0.1:55455/test"
I would expect the proxied version to behave just as well as the non-proxied version, and sustain the performance over time.
The complete sample code follows.
package main
import (
"fmt"
"log"
"net/http"
)
func main() {
tr := &http.Transport{
DisableCompression: true,
DisableKeepAlives: false,
}
client := &http.Client{Transport: tr}
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
send(r, client)
fmt.Fprintf(w, "OK")
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
func send(r *http.Request, client *http.Client) int {
req, err := http.NewRequest("GET", "http://localhost:55455" + r.URL.Path, nil)
if err != nil {
log.Fatal(err)
return 0
}
resp, err := client.Do(req)
if err != nil {
log.Fatal(err)
return 0
}
if resp == nil {
return 0
}
return 1
}
Eventually the code should send the request to multiple servers and process their answers, returning an int with the result. But I'm stuck at this step of just making the call.
What am I doing horribly wrong?