Profiling is an essential tool in identifying performance bottlenecks and improving the efficiency of a web server. Golang, with its built-in profiling support, provides a powerful profiling mechanism to identify and resolve performance issues. In this article, we will explore how to use profiling in Golang web servers with the Chi router.
Why using Chi router? Chi is a lightweight, high-performance router for Golang web servers. It is built on top of the net/http package and provides a simple and elegant way to define routes and middleware. Chi is also compatible with the standard Golang http.Handler interface, making it easy to integrate with other Golang packages.
Step 1: Import the Required Packages
Before we can start using profiling in our Golang web server, we need to import the necessary packages. In addition to the standard net/http package, we also need to import the pprof package ( in this case we are using middleware chi), which provides the profiling functionality.
import (
"net/http"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/chi/v5"
)
Step 2: Define the Routes
Next, we need to define the routes for our web server using the Chi router. We will create two routes – one for serving the web pages and another for serving the profiling data.
To enable profiling in our Golang web server, we need to add the profiling middleware to the router. The profiling middleware will intercept requests to the /debug
endpoint and serve the profiling data.
func main() {
r := chi.NewRouter()
// Define the routes for serving web pages
r.Get("/memleak", nonClosedBufferHandler)
// Define the routes for serving profiling data
r.Mount("/debug", middleware.Profiler())
// Start the web server
http.ListenAndServe(":8080", r)
}
func nonClosedBufferHandler(w http.ResponseWriter, r *http.Request) {
data := make([]byte, 1024*1024)
w.Write(data)
}
Step 3:
Add workload on specific endpoint that we need to check. For example hit /memleak
endpoint using hey.
hey http://localhost:8080/memleak
Step 4: Generate Profiling Data
Once the profiling middleware is enabled, we can generate profiling data by making requests to the /debug/pprof
endpoint. For example, to generate a CPU profile, we can make a request to /debug/pprof/profile
.
$ go tool pprof http://localhost:8080/debug/pprof/profile
$ Type: cpu
Time: Mar 29, 2023 at 6:45am (WIB)
Duration: 30s, Total samples = 50ms ( 0.17%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof) top
Showing top 10 nodes out of 27
flat flat% sum% cum cum%
50ms 100% 100% 50ms 100% syscall.syscall
0 0% 100% 10ms 20.00% bufio.(*Reader).Peek
0 0% 100% 10ms 20.00% bufio.(*Reader).fill
0 0% 100% 20ms 40.00% bufio.(*Writer).Flush
0 0% 100% 20ms 40.00% internal/poll.(*FD).Close
0 0% 100% 10ms 20.00% internal/poll.(*FD).Read
0 0% 100% 20ms 40.00% internal/poll.(*FD).Write
0 0% 100% 20ms 40.00% internal/poll.(*FD).decref
0 0% 100% 20ms 40.00% internal/poll.(*FD).destroy
0 0% 100% 30ms 60.00% internal/poll.ignoringEINTRIO (inline)
This will generate a CPU profile and open the pprof interactive shell. Or if you need visualization in browser for example using localhost in port 9090 localhost:9090
go tool pprof -http=localhost:9090 http://localhost:3000/debug/pprof/profile
From here, we can analyze the profiling data to identify performance bottlenecks in our web server.
Conclusion
Profiling is an essential tool for identifying and resolving performance issues in Golang web servers. With the Chi router and the pprof package, we can easily enable profiling in our web server and generate profiling data to analyze. By identifying and resolving performance bottlenecks, we can improve the efficiency and reliability of our Golang web applications.