Pick a depth. Each prompt opens in your AI pre-loaded with the lesson. Click a row to preview the prompt.
A single HTTP request is not one event — it is a pipeline of up to seven distinct phases: DNS resolution, TCP connection, TLS handshake, request send, server think-time, response header receipt (TTFB), and body transfer. Slowness can hide in any one of these phases, and the fix for each is completely different. A request that takes 800 ms because of DNS misconfiguration needs a DNS fix, not a database index. A request slowed by TLS renegotiation needs session resumption, not a cache layer. Without knowing which phase is slow you are guessing — and the wrong guess wastes a sprint.
Percentile statistics expose the shape of a latency distribution that averages permanently hide. A workload where 990 requests take 10 ms and 10 take 5,000 ms produces a 59 ms average — a number that reads as healthy while 1% of users wait five seconds. Collecting a sample of 200 requests and comparing p50, p95, and p99 makes that tail visible as a concrete number rather than an invisible outlier.
https://httpbin.org/delay/0.5 — the time_starttransfer field is your TTFB. Subtract time_appconnect from it to isolate pure server think-time.// main.go — print per-phase timings by tracing the HTTP connection
package main
import (
"crypto/tls"
"fmt"
"io"
"net/http"
"net/http/httptrace"
"time"
)
func main() {
url := "https://jsonplaceholder.typicode.com/posts/1"
var (
t0 = time.Now()
dnsStart, dnsEnd, connStart, connEnd time.Time
tlsStart, tlsEnd, reqWritten, firstByte time.Time
)
trace := &httptrace.ClientTrace{
DNSStart: func(_ httptrace.DNSStartInfo) { dnsStart = time.Now() },
DNSDone: func(_ httptrace.DNSDoneInfo) { dnsEnd = time.Now() },
ConnectStart: func(_, _ string) { connStart = time.Now() },
ConnectDone: func(_, _ string, _ error) { connEnd = time.Now() },
TLSHandshakeStart: func() { tlsStart = time.Now() },
TLSHandshakeDone: func(_ tls.ConnectionState, _ error) { tlsEnd = time.Now() },
WroteRequest: func(_ httptrace.WroteRequestInfo) { reqWritten = time.Now() },
GotFirstResponseByte: func() { firstByte = time.Now() },
}
req, _ := http.NewRequest("GET", url, nil)
req = req.WithContext(httptrace.WithClientTrace(req.Context(), trace))
resp, _ := http.DefaultClient.Do(req)
io.Copy(io.Discard, resp.Body)
resp.Body.Close()
total := time.Since(t0)
ms := func(a, b time.Time) int64 { return b.Sub(a).Milliseconds() }
fmt.Printf("DNS lookup: %3d ms\n", ms(dnsStart, dnsEnd))
fmt.Printf("TCP connect: %3d ms\n", ms(connStart, connEnd))
fmt.Printf("TLS handshake: %3d ms\n", ms(tlsStart, tlsEnd))
fmt.Printf("Request send: %3d ms\n", ms(tlsEnd, reqWritten))
fmt.Printf("Server (TTFB): %3d ms\n", ms(reqWritten, firstByte))
fmt.Printf("Transfer: %3d ms\n", ms(firstByte, t0.Add(total)))
fmt.Printf("Total: %3d ms\n", total.Milliseconds())
}go run main.go