Skip to content

Instantly share code, notes, and snippets.

@heltonmarx
Last active June 27, 2022 18:11
Show Gist options
  • Save heltonmarx/96281301e307e36e24c8101b19193452 to your computer and use it in GitHub Desktop.
Save heltonmarx/96281301e307e36e24c8101b19193452 to your computer and use it in GitHub Desktop.
Transport TIME_WAIT load test
netstat -n | grep -i 8080 | grep -i time_wait | wc -l
package main
import (
"context"
"fmt"
"html"
"io"
"io/ioutil"
"log"
"net"
"net/http"
"time"
"golang.org/x/net/http2"
)
func newV1Client() (*http.Client, error) {
tr := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
}
if err := http2.ConfigureTransport(tr); err != nil {
return nil, err
}
fmt.Printf("\nV1: \n")
showTransport(tr)
return &http.Client{
Transport: tr,
Timeout: 30 * time.Second,
}, nil
}
func newV2Client() (*http.Client, error) {
tr := &http.Transport{
DialContext: (&net.Dialer{
Timeout: 30 * time.Second,
KeepAlive: 30 * time.Second,
DualStack: true,
}).DialContext,
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
TLSHandshakeTimeout: 10 * time.Second,
ExpectContinueTimeout: 1 * time.Second,
ForceAttemptHTTP2: true,
MaxIdleConnsPerHost: 100,
}
if err := http2.ConfigureTransport(tr); err != nil {
return nil, err
}
fmt.Printf("\nV2: \n")
showTransport(tr)
return &http.Client{
Transport: tr,
Timeout: 30 * time.Second,
}, nil
}
func server() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
time.Sleep(time.Millisecond * 50)
fmt.Fprintf(w, "hello, %q", html.EscapeString(r.URL.Path))
})
go http.ListenAndServe(":8080", nil)
}
func loadtest(ctx context.Context, client *http.Client) {
count := 0
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "http://localhost:8080/", nil)
if err != nil {
msg := fmt.Sprintf("Go error: %v\n", err)
panic(msg)
}
for {
resp, err := client.Do(req)
if err != nil {
msg := fmt.Sprintf("Got error: %v", err)
panic(msg)
}
io.Copy(ioutil.Discard, resp.Body)
resp.Body.Close()
log.Printf("Finished GET request #%v", count)
count = count + 1
}
}
func main() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
client, err := newV2Client()
if err != nil {
log.Fatal(err)
}
server()
n := 100
for i := 0; i < n; i++ {
go loadtest(ctx, client)
}
time.Sleep(time.Second * 2400)
}
func showTransport(tr *http.Transport) {
fmt.Printf(" MaxIdleConns: %v\n", tr.MaxIdleConns)
fmt.Printf(" IdleConnTimeout: %v\n", tr.IdleConnTimeout)
fmt.Printf(" TLSHandshakeTimeout: %v\n", tr.TLSHandshakeTimeout)
fmt.Printf(" ExpectContinueTimeout: %v\n", tr.ExpectContinueTimeout)
fmt.Printf(" MaxIdleConnsPerHost: %v\n", tr.MaxIdleConnsPerHost)
fmt.Printf(" ForceAttemptHTTP2: %v\n", tr.ForceAttemptHTTP2)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment