Thank you for providing this guide, I’m new to Golang and happy to find any useful information.
I also read this article, it’s about how performance monitoring in Golang can be conducted and how to make changes that will affect overall performance.
Long story short, they started the profiler:
defer profile.Start(profile.MemProfileRate(1), profile.ProfilePath(".")).Stop()
profile.MemProfileRate(1)` configure profiler to collect information about each allocation.
Then they started the service to make a single request, analyzed appeared mem.pprof file with the command go tool pprof mem.pprof. Next they went command top main:
Active filters:
focus=main
Showing nodes accounting for 6MB, 97.61% of 6.15MB total:
Dropped 51 nodes (cum <= 0.03MB)
flat flat% sum% cum cum%
6MB 97.61% 97.61% 6MB 97.61% bytes.makeSlice
0 0% 97.61% 6MB 97.61% bytes.(*Buffer).ReadFrom
0 0% 97.61% 6MB 97.61% bytes.(*Buffer).grow
0 0% 97.61% 6MB 97.61% io/ioutil.ReadAll
0 0% 97.61% 6MB 97.61% io/ioutil.readAll
0 0% 97.61% 6MB 97.61% main.main.func1
0 0% 97.61% 6MB 97.61% net/http.(*ServeMux).ServeHTTP
0 0% 97.61% 6MB 97.61% net/http.(*conn).serve
0 0% 97.61% 6MB 97.61% net/http.HandlerFunc.ServeHTTP
0 0% 97.61% 6MB 97.61% net/http.serverHandler.ServeHTTP
After that they run command list main.main.func1 to see the allocation per line:
Total: 6.15MB
ROUTINE ======================== main.main.func1 in /Users/user/go/src/article/main.go
0 6MB (flat, cum) 97.61% of Total
. . 30:
. . 31:func main() {
. . 32: defer profile.Start(profile.MemProfileRate(1), profile.ProfilePath(".")).Stop()
. . 33:
. . 34: http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
. 6MB 35: bb, _ := ioutil.ReadAll(r.Body)
. . 36: rbody := bytes.NewReader(bb)
. . 37: n, _ := countLetters(rbody)
. . 38: _, _ = fmt.Fprint(w, n)
. . 39: })
. . 40:
As it turned out, the line 35 is reading the whole body of requests, instead of just reading characters (counting characters is the function of the service). So they replaced lines 35 and 36 with rbody := bufio.NewReader(bb). It provided Reader, that is going to optimize performance:
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
rbody := bufio.NewReader(r.Body)
n, _ := countLetters(rbody)
_, _ = fmt.Fprint(w, n)
})
Thus, resource consumption was significantly reduced, with only several actions made.
A great example of how important performance monitoring can be.