<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          通過例子學(xué) Go pprof

          共 1661字,需瀏覽 4分鐘

           ·

          2022-03-10 20:07

          對于大多數(shù) Gopher 而言,一般平時最主要的工作內(nèi)容除了實現(xiàn)各種無聊的業(yè)務(wù)邏輯之外,剩下的就是解決各種瑣碎的問題。比如:查詢性能瓶頸在哪里?查詢內(nèi)存泄漏在哪里?好在 pprof 是處理此類問題的利器,共有兩套標(biāo)準(zhǔn)庫,分別適用于不同的場景:

          • runtime/pprof[1]:采集工具型應(yīng)用運行數(shù)據(jù)進(jìn)行分析
          • net/http/pprof[2]:采集服務(wù)型應(yīng)用運行時數(shù)據(jù)進(jìn)行分析

          命令行工具「go test」就包含了 runtime/pprof,相關(guān)參數(shù)請參考「go help testflag」:

          shell>?go?test?-cpuprofile?cpu.out?-memprofile?mem.out?-bench?.

          不過和 runtime/pprof 相比,更常用的是 net/http/pprof,接下來我們主要通過它來解決一些常見問題,想要激活 net/http/pprof 的話很簡單,只要導(dǎo)入對應(yīng)的包并啟動服務(wù)即可:

          import?_?"net/http/pprof"

          func?main()?{
          ?_?=?http.ListenAndServe("localhost:6060",?nil)
          }

          需要注意的是,千萬別讓外網(wǎng)訪問到 pprof,否則可能會導(dǎo)致出現(xiàn)安全問題。有興趣的讀者可以嘗試通過 google 搜索「intitle:/debug/pprof/ inurl:/debug/pprof/」看看反面例子。

          Profile

          pprof 預(yù)置了很多種不同類型的 profile,我們可以按照自己的需要選擇:

          • allocs:A sampling of all past memory allocations
          • block:Stack traces that led to blocking on synchronization primitives
          • goroutine:Stack traces of all current goroutines
          • heap:A sampling of memory allocations of live objects
          • mutex:Stack traces of holders of contended mutexes
          • profile:CPU profile
          • threadcreate:Stack traces that led to the creation of new OS threads

          其中最常用的是 profile 和 heap,分別用來診斷 CPU 和內(nèi)存問題。

          CPU profiling

          演示代碼模擬了 CPU 密集型任務(wù)(onCPU)和耗時的網(wǎng)絡(luò)請求(offCPU):

          package?main

          import?(
          ?"log"
          ?"net/http"
          ?_?"net/http/pprof"
          ?"runtime"
          ?"time"

          ?"github.com/felixge/fgprof"
          )

          const?cpuTime?=?1000?*?time.Millisecond

          func?main()?{
          ?runtime.SetBlockProfileRate(1)
          ?runtime.SetMutexProfileFraction(1)

          ?go?func()?{
          ??http.Handle("/debug/fgprof",?fgprof.Handler())
          ??log.Println(http.ListenAndServe(":6060",?nil))
          ?}()

          ?for?{
          ??cpuIntensiveTask()
          ??slowNetworkRequest()
          ?}
          }

          func?cpuIntensiveTask()?{
          ?start?:=?time.Now()

          ?for?time.Since(start)?<=?cpuTime?{
          ??for?i?:=?0;?i?1000;?i++?{
          ???_?=?i
          ??}
          ?}
          }

          func?slowNetworkRequest()?{
          ?resp,?err?:=?http.Get("http://httpbin.org/delay/1")

          ?if?err?!=?nil?{
          ??log.Fatal(err)
          ?}

          ?defer?resp.Body.Close()
          }

          通過 go tool pprof 查看 /debug/pprof/profile:

          go?tool?pprof?-http?:8080?http://localhost:6060/debug/pprof/profile

          結(jié)果發(fā)現(xiàn) profile 只能檢測到 onCPU(也就是 cpuIntensiveTask)部分,卻不能檢測到 offCPU (也就是 slowNetworkRequest)部分:

          profile

          為了檢測 offCPU 部分,我們引入 fgprof,通過 go tool pprof 查看 /debug/fgprof:

          go?tool?pprof?-http?:8080?http://localhost:6060/debug/fgprof

          結(jié)果發(fā)現(xiàn) fgprof 不僅能檢測到 onCPU(也就是 cpuIntensiveTask)部分,還能檢測到 offCPU (也就是 slowNetworkRequest)部分:

          fgprof

          實際應(yīng)用中,最好對你的瓶頸是 onCPU 還是 offCPU 有一個大體的認(rèn)識,進(jìn)而選擇合適的工具,如果不確定就直接用 fgprof,不過需要注意的是 fgprof 對性能的影響較大。

          Memory profiling

          演示代碼模擬了一段有內(nèi)存泄漏問題的程序:

          package?main

          import?(
          ?"log"
          ?"net/http"
          ?_?"net/http/pprof"
          ?"time"
          )

          func?main()?{
          ?go?func()?{
          ??log.Println(http.ListenAndServe(":6060",?nil))
          ?}()

          ?for?{
          ??leak()
          ?}
          }

          func?leak()?{
          ?s?:=?make([]string,?10)

          ?for?i?:=?0;?i?10000000;?i++?{
          ??s?=?append(s,?"leak")

          ??if?(i?%?10000)?==?0?{
          ???time.Sleep(1?*?time.Second)
          ??}

          ??_?=?s
          ?}
          }

          通過 go tool pprof 查看 /debug/pprof/head(這次不用 web,用命令行):

          heap

          通過 top 命令可以很直觀的看出哪里可能出現(xiàn)了內(nèi)存泄漏問題。不過這里有一個需要說明的問題是內(nèi)存占用大的地方本身可能是正常的,與內(nèi)存的絕對值大小相比,我們更應(yīng)該關(guān)注的是不同時間點內(nèi)存相對變化大小,這里可以使用參數(shù) base 或者 diff_base:

          heap

          本文篇幅有限,無法列舉更多的例子,有興趣的讀者推薦參考「golang pprof 實戰(zhàn)[3]」。

          參考資料

          [1]

          runtime/pprof: https://golang.org/pkg/runtime/pprof/

          [2]

          net/http/pprof: https://golang.org/pkg/net/http/pprof/

          [3]

          golang pprof 實戰(zhàn): https://blog.wolfogre.com/posts/go-ppof-practice/


          瀏覽 38
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国模无码在线 | 欧美国产精品一区 | 走光无码一区二区三区 | 日韩精品日韩毛片无码 | 成人三级在线观看 |