How do you expose pprof in a production service, and what are the security and design gotchas?
Question 369MediumGo 1.22 to 1.25
Importing net/http/pprof for its side effect registers handlers under /debug/pprof/ on http.DefaultServeMux. The gotcha: if your public API server also uses DefaultServeMux, you've just exposed profiling (and goroutine stacks, command line, heap contents) to the internet. The fix is to serve pprof on a separate, internal-only listener.
import (
"log"
"net/http"
"net/http/pprof"
)
func startDebugServer() {
mux := http.NewServeMux()
mux.HandleFunc("/debug/pprof/", pprof.Index)
mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
mux.HandleFunc("/debug/pprof/profile", pprof.Profile)
mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
mux.HandleFunc("/debug/pprof/trace", pprof.Trace)
go func() {
// bind to localhost / internal interface only
log.Println(http.ListenAndServe("127.0.0.1:6060", mux))
}()
}
Then: go tool pprof -http=:8080 http://127.0.0.1:6060/debug/pprof/profile?seconds=30. Named profiles (heap, goroutine, block, mutex, allocs, threadcreate) are served by pprof.Index. Interviewer is looking for: awareness of the DefaultServeMux leak, that CPU profiling has low overhead (~a few %) and is safe to run in prod on demand, and that block/mutex profiles are off by default.
More on Performance, Profiling & Testing
- Q370How does the Go CPU profiler work, and what is the difference between "flat" and "cum" in pprof output?
- Q371Explain inuse_space vs alloc_space in a heap profile. Which do you use to find a memory leak vs GC pressure?
- Q372How would you detect and diagnose a goroutine leak?
- Q373What do the block and mutex profiles measure, how do you enable them, and how do they differ?
- Q374When would you use go tool trace instead of pprof? What can it show that profiles cannot?
- Q375What is testing.B.Loop (Go 1.24) and why is it preferred over the classic b.N loop?