本文介紹 golang 如何做性能分析。

對服務做了基準性能測試後,如果服務出現問題,可以通過性能分析工具,查出消耗資源的瓶頸,並做針對性的性能優化。

Golang 語言也爲我們提供了方便的性能分析工具pprof,方便我們做必要的服務優化。pprof 可以做cpu分析,統計所有調用方法執行的時間片(通過採樣); 可以查看內存分配,找到是否有內存泄漏,哪裏泄露了(調用棧);還可以查看Block、事件調用,互斥鎖等。可謂麻雀雖小,五臟俱全。Golang 提供了兩種分析的工具,一種是web工具,直接引入即可;另一種是命令行交互工具,需要抓取prof 數據,再做詳細分析。

WEB 工具

golang 性能分析工具主要有幾種,最常用的是使用web 界面的工具。我們舉個簡單的例子,將一個map數據做編碼,編碼100w次,例子如下:

package main

import "encoding/json"
import _ "net/http/pprof"
import "net/http"

func main() {
  mapData := 
  mapData := map[string]string{
    "abcdefg1":  "aaaaaaaaaaaaaaaaaaaa",
    "abcdefg2":  "aaaaaaaaaaaaaaaaaaaa",
    "abcdefg3":  "aaaaaaaaaaaaaaaaaaaa",
    "abcdefg4":  "aaaaaaaaaaaaaaaaaaaa",
    "abcdefg5":  "aaaaaaaaaaaaaaaaaaaa",
    "abcdefg6":  "aaaaaaaaaaaaaaaaaaaa",
    "abcdefg7":  "aaaaaaaaaaaaaaaaaaaa",
    "abcdefg8":  "aaaaaaaaaaaaaaaaaaaa",
    "abcdefg9":  "aaaaaaaaaaaaaaaaaaaa",
    "abcdefg10": "aaaaaaaaaaaaaaaaaaaa",
  }

  go func() {
    for i := 0; i < 100000000; i++ {
      _, _ = json.Marshal(data)
    }
  }()
  http.ListenAndServe("0.0.0.0:8080", nil)
}

引入 "net/http/pprof" 包,將自動在默認的http中添加相關 pprof 的處理方法(當然也可以自己添加了)。

我們通過訪問 /debug/pprof/ 就可以打開對應的web 界面。

  • allocs 過去所有內存分配的採樣。
  • block 查看阻塞同步的堆棧
  • cmdline 當前進程的命令行
  • goroutine 所有協程的調用棧
  • heap 當前活動對象的內存分配
  • mutex 競態互斥鎖的調用棧
  • profile 獲取一個30s(可以通過seconds 參數指定)的cpu 採樣prof 文件 (可以用 go tool pprof 分析)
  • threadcreate 導致創建了新系統線程的調用棧
  • trace 抓一個當前執行的trace包,可以捕獲各種事件(可以用go tool trace 做可視化分析)

命令行交互

命令行工具,需要先抓取一段採樣數據,採樣數據可以通過web 的 profile 鏈接直接下載,也可以不啓動web服務,直接採樣。直接採樣的好處是,可以直接採樣我們需要優化的代碼段的數據,而web採樣的數據不一定會抓到我們執行的代碼段(畢竟是通過採樣實現的)。下面我們寫一個直接採樣的例子:

package main

import "encoding/json"
import "runtime/pprof"
import "os"
import "log"

func main() {
  cpuprofile := "json_map.prof"
  mapData := map[string]string{
      "abcdefg1":  "aaaaaaaaaaaaaaaaaaaa",
      "abcdefg2":  "aaaaaaaaaaaaaaaaaaaa",
      "abcdefg3":  "aaaaaaaaaaaaaaaaaaaa",
      "abcdefg4":  "aaaaaaaaaaaaaaaaaaaa",
      "abcdefg5":  "aaaaaaaaaaaaaaaaaaaa",
      "abcdefg6":  "aaaaaaaaaaaaaaaaaaaa",
      "abcdefg7":  "aaaaaaaaaaaaaaaaaaaa",
      "abcdefg8":  "aaaaaaaaaaaaaaaaaaaa",
      "abcdefg9":  "aaaaaaaaaaaaaaaaaaaa",
      "abcdefg10": "aaaaaaaaaaaaaaaaaaaa",
  }

  if cpuprofile != "" {
      f, err := os.Create(cpuprofile)
      if err != nil {
          log.Fatal(err)
      }

      pprof.StartCPUProfile(f)
      defer pprof.StopCPUProfile()
  }

  for i := 0; i < 1000000; i++ {
      _, _ = json.Marshal(mapData)
  }
}

然後我們通過如下命令進入交互模式:

[root@localhost pprof]# go tool pprof json_map.prof
File: json_map_1
Type: cpu
Time: Apr 11, 2020 at 6:49pm (CST)
Duration: 7.38s, Total samples = 7.12s (96.46%)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)

交互模式,也提供了豐富的命令查看prof文件中的數據,例如如下使用top10 查看代碼執行cpu佔比top10 的方法。

(pprof) top10
Showing nodes accounting for 3470ms, 48.74% of 7120ms total
Dropped 78 nodes (cum <= 35.60ms)
Showing top 10 nodes out of 87
      flat  flat%   sum%        cum   cum%
     570ms  8.01%  8.01%     1100ms 15.45%  encoding/json.(*encodeState).string
     550ms  7.72% 15.73%     1850ms 25.98%  runtime.mallocgc
     460ms  6.46% 22.19%      460ms  6.46%  runtime.memmove
     410ms  5.76% 27.95%      540ms  7.58%  runtime.mapaccess2
     320ms  4.49% 32.44%      350ms  4.92%  runtime.heapBitsSetType
     290ms  4.07% 36.52%      970ms 13.62%  runtime.typedmemmove
     230ms  3.23% 39.75%      230ms  3.23%  runtime.nextFreeFast
     220ms  3.09% 42.84%      220ms  3.09%  runtime.memclrNoHeapPointers
     210ms  2.95% 45.79%      210ms  2.95%  cmpbody
     210ms  2.95% 48.74%     6720ms 94.38%  encoding/json.mapEncoder.encode

還有其他功能,例如繪製調用圖,內存分配圖等,可以通過help查看:

除此之外, go tool profile 還有另外的打開模式。例如,通過web服務查看prof 文件。

執行如下命令,通過web服務查看prof文件:

[root@localhost pprof]# go tool pprof -http=:8080 json_map.prof

可以查看進程調用圖,看到各調用函數的執行事件。

可以查看火焰圖,具體分析哪些方法有優化空間。

  • 還可以查看Peek (調用者與被調用者匹配關係)

  • 可以從源碼角度查看執行時間佔比。

  • 也可以通過反彙編的代碼角度查看執行時間佔比。

除此之外,還可以命令行方式直接抓取web工具中的profile 數據做分析。(實際看來和自己抓取沒什麼區別,只是方便了而已)

其他

golang 目前提供的性能分析工具已經比較齊全了。本文只是對目前已經使用的功能做簡單總結,其他功能還待我們一起去探索。

本文使用的go版本爲1.13

下一篇將對 go tool 的另一神器 go tool trace 做簡單總結。

歡迎關注我們的微信公衆號,每天學習Go知識

相關文章