Golang程序診斷

簡介

Go生態系統提供了一整套用於診斷Go程序中的邏輯和性能問題的API和工具。該篇文章總結了可用的工具,並幫助Go用戶針對他們的特定問題選擇合適的工具。html

診斷解決方案能夠分爲如下幾類:前端

  • Profiling: Profiling工具分析Go程序的複雜性和成本,例如其內存使用狀況和常常調用的函數,以識別Go程序的最耗費資源的部分。
  • Tracing: Tracing是一種工具代碼,能夠在調用或用戶請求的整個生命週期中分析延遲。跟蹤提供了每一個組件對系統整體延遲形成多少延遲的概述。跟蹤能夠跨越多個Go進程。
  • Debugging: Debugging容許咱們暫停Go程序並檢查其執行。程序狀態和流程能夠經過調試來驗證。
  • Runtime statistics and events: 運行時狀態和事件的收集和分析提供了Go程序運行情況的高級概述。指標的峯/谷有助於咱們識別吞吐量,利用率和性能的變化。

注意:某些診斷工具可能會相互干擾。例如,內存分析會影響CPU profiles,goroutine 阻塞分析會影響調度程序跟蹤。一次只使用一種工具以得到更精確的信息。git

Profiling

分析對於識別消耗資源嚴重或常常調用的代碼段頗有用。 Go運行時以pprof可視化工具所需的格式提供概要分析數據。能夠在測試過程當中經過go test或 net/http/pprof 程序包中提供的端點收集性能分析數據。用戶須要收集性能分析數據並使用pprof工具來過濾和可視化代碼路徑。github

runtime/pprof 軟件包提供的預約義profiles:golang

  • cpu: CPU profile肯定了程序在真實消耗CPU時間片(而不是在睡眠或等待I/O)所花費的時間。
  • heap: heap profile報告內存分配樣本;用於監視當前和歷史內存使用狀況,並檢查內存泄漏。
  • threadcreate: 線程建立profile報告了致使建立新OS線程的程序部分。
  • goroutine: Goroutine profile報告全部當前goroutine的堆棧跟蹤。
  • block: Block profile顯示goroutine在哪裏阻塞同步原語(包括計時器通道)的等待。默認狀況下未啓用Block profile;使用runtime.SetBlockProfileRate啓用它。
  • mutex: Mutex profile報告鎖爭用。若是您認爲因爲互斥鎖爭用而沒法充分利用CPU,請使用此profile。Mutex profile默認狀況下未啓用,請參見runtime.SetMutexProfileFraction啓用它。

我還可使用哪些其餘分析器來分析Go程序?web

在Linux上,可使用perf工具來分析Go程序。 Perf能夠分析和解散cgo /SWIG代碼和內核,所以深刻了解本機/內核性能瓶頸可能頗有用。在macOS上,Instruments套件可用於profile Go程序。數據庫

我能夠profile個人生產服務嗎?編程

是。在生產環境中對程序進行概要分析是安全的,可是啓用某些概要文件(例​​如CPU概要文件)會增長成本。您應該指望看到性能降低。能夠經過在生產以前打開Profiler來測量Profiler的開銷來估算性能損失。後端

您可能須要按期分析生產服務。特別是在具備單個進程多個副本的系統中,按期選擇隨機副本是一個安全的選擇。選擇一個生產過程,每隔Y秒將其概要分析X秒,並保存結果以進行可視化和分析;而後按期重複。能夠手動或自動查看結果以發現問題。profile的收集可能會相互干擾,所以建議一次僅收集一個profile。安全

可視化分析數據的最佳方法是什麼?
Go工具使用go tool pprof提供profile數據的文本,圖形和callgrind可視化。閱讀Profiling Go程序以查看它們的運行狀況。

以文本形式列出最消耗資源的調用
pprof-text.png

將最消耗資源的調用可視化爲圖表
pprof-dot.png

Weblist視圖在HTML頁面中逐行顯示源代碼最消耗資源的部分。在下面的示例中,運行時花費了530毫秒。runtime.concatstrings和清單中列出了每行的成本。

將最消耗資源的調用可視化爲weblist
pprof-weblist.png

可視化輪廓數據的另外一種方法是火焰圖。火焰圖使您能夠在特定的祖先路徑中移動,所以能夠放大/縮小代碼的特定部分。上游pprof支持火焰圖。

flame.png

我是否限於內置profiles?

除了運行時提供的功能外,Go用戶還能夠經過pprof.Profile建立其自定義profile,並使用現有工具進行檢查。

我能夠在其餘路徑和端口上提供事件探查器處理程序(/debug/pprof/ ...)嗎?

是。 net/http/pprof軟件包默認狀況下將其處理程序註冊到默認的多路複用器,可是您也可使用從軟件包中導出的處理程序本身註冊它們。

例如,如下示例將在 /custom_debug_path/profile上的:7777上提供pprof.Profile處理程序:

package main

import (
    "log"
    "net/http"
    "net/http/pprof"
)

func main() {
    mux := http.NewServeMux()
    mux.HandleFunc("/custom_debug_path/profile", pprof.Profile)
    log.Fatal(http.ListenAndServe(":7777", mux))
}

Tracing

跟蹤是一種工具代碼,能夠分析整個調用鏈的整個生命週期中的延遲。 Go提供golang.org/x/net/trace軟件包做爲每一個Go節點的最小跟蹤後端,並提供帶有簡單儀表板的最小檢測庫。 Go還提供了一個執行跟蹤器,以跟蹤一個間隔內的運行時事件。

Tracing 能夠在如下方面幫助到咱們:

  • 在Go流程中檢測和分析應用程序延遲。
  • 在一連串的通話中衡量特定通話的費用。
  • 找出利用率和性能改進。若是不跟蹤數據,瓶頸並不老是很明顯。

在單片系統中,從程序的構建塊中收集診斷數據相對容易。全部模塊都生活在一個過程當中,並共享公共資源來報告日誌,錯誤和其餘診斷信息。一旦您的系統超出了單個進程並開始分佈,就很難跟蹤從前端Web服務器到其全部後端的調用,直到將響應返回給用戶爲止。在這裏,分佈式跟蹤對儀器和分析生產系統起着重要做用。

分佈式跟蹤是一種工具代碼,能夠分析用戶請求整個生命週期中的延遲。當系統是分佈式的而且常規的性能分析和調試工具沒法擴展時,您可能但願使用分佈式跟蹤工具來分析用戶請求和RPC的性能。

分佈式跟蹤在如下幾個方面能夠幫助到咱們:

  • 大型系統中的儀器和配置文件應用程序延遲。
  • 跟蹤用戶請求生命週期內的全部RPC,並查​​看僅在生產中可見的集成問題。
  • 找出能夠應用於咱們的系統的性能改進。在收集跟蹤數據以前,許多瓶頸並不明顯。

Go生態系統爲每一個跟蹤系統和與後端無關的數據庫提供了各類分佈式跟蹤庫。

有沒有一種方法能夠自動攔截每一個函數調用並建立跟蹤?

Go沒法提供一種自動攔截每一個函數調用並建立跟蹤範圍的方法。您須要手動檢測代碼以建立,結束和註釋跨度。

我應該如何在Go庫中傳播跟蹤頭?

您能夠在context.Context中傳播跟蹤標識符和標記。業界尚無規範的跟蹤鍵或跟蹤頭的通用表示形式。每一個跟蹤提供者都有責任在其Go庫中提供傳播實用程序。

標準庫或運行時中還有哪些其餘低級事件能夠包含在跟蹤中?

標準庫和運行時正嘗試公開一些其餘API,以在發生低級內部事件時進行通知。例如,httptrace.ClientTrace提供API以在傳出請求的生命週期中跟蹤低級事件。正在進行中的工做是從運行時執行跟蹤器中檢索低級運行時事件,並容許用戶定義和記錄其用戶事件。

Debugging

調試是肯定程序行爲異常的過程。調試器使咱們可以瞭解程序的執行流程和當前狀態。調試有幾種樣式。本節僅關注將調試器附加到程序和core dump調試。

Go用戶一般使用如下調試器:

  • Delve: Delve是Go編程語言的調試器。它支持Go的運行時概念和內置類型。 Delve試圖成爲Go程序的全功能可靠調試器。
  • GDB: Go經過標準的Go編譯器和Gccgo提供了GDB支持。堆棧管理,線程和運行時所包含的方面與執行模型有很大不一樣,GDB但願它們會混淆調試器,即便使用gccgo編譯程序也是如此。即便可使用GDB調試Go程序,它也不是理想的選擇,而且可能會形成混亂。

調試器與Go程序的配合狀況如何?

gc編譯器執行優化,例如函數內聯和變量註冊。這些優化有時會使調試器的調試更加困難。正在進行不斷的努力來改善爲優化的二進制文件生成的DWARF信息的質量。在這些改進可用以前,咱們建議在構建要調試的代碼時禁用優化。如下命令生成沒有編譯器優化的軟件包:

$ go build -gcflags=all="-N -l"

做爲改進工做的一部分,Go 1.10引入了新的編譯器標誌-dwarflocationlists。該標誌使編譯器添加位置列表,以幫助調試器使用優化的二進制文件。如下命令使用DWARF位置列表構建具備優化的軟件包:

$ go build -gcflags="-dwarflocationlists=true"

推薦的調試器用戶界面是什麼?

儘管delve和gdb都提供了CLI,可是大多數編輯器集成和IDE都提供了特定於調試的用戶界面。

可使用Go程序進行過後調試嗎?

core dump文件是一個文件,其中包含正在運行的進程的內存dump及其進程狀態。它主要用於程序的過後調試,並在程序仍在運行時瞭解其狀態。這兩種狀況使core dump的調試成爲進行過後分析和分析生產服務的良好診斷工具。能夠從Go程序中獲取core文件,並使用delve或gdb進行調試,有關逐步指南,請參見core dump調試頁面。

Runtime statistics and events

運行時爲用戶提供內部事件的統計信息和報告,以在運行時級別診斷性能和利用率問題。

用戶能夠監視這些統計信息,以更好地瞭解Go程序的總體運行情況和性能。一些常常監視的統計信息和狀態:

  • runtime.ReadMemStats報告與堆分配和垃圾收集相關的指標。內存統計信息對於監視進程正在消耗多少內存資源,進程是否能夠充分利用內存以及捕獲內存泄漏頗有用。
  • debug.ReadGCStats讀取有關垃圾收集的統計信息。查看在GC暫停上花費了多少資源是頗有用的。它還報告了垃圾收集器暫停和暫停時間百分比的時間線。
  • debug.Stack返回當前的堆棧跟蹤。堆棧跟蹤對於查看當前正在運行多少個goroutine,它們在作什麼以及是否被阻塞很是有用。
  • debug.WriteHeapDump暫停全部goroutine的執行,並容許您將堆dump到文件中。堆dump是給定時間Go進程內存的快照。它包含全部分配的對象以及goroutine,finalizer等。
  • runtime.NumGoroutine返回當前goroutine的數量。能夠監視該值以查看是否使用了足夠的goroutine,或者檢測goroutine泄漏。

Execution tracer

Go附帶了一個運行時執行跟蹤程序,以捕獲各類運行時事件。調度,系統調用,垃圾回收,堆大小和其餘事件由運行時收集,而且能夠經過go工具跟蹤進行可視化。執行跟蹤器是檢測延遲和利用率問題的工具。您能夠檢查CPU的利用率,以及什麼時候網絡鏈接或系統調用會致使goroutine搶佔。

跟蹤器在一下幾個方面能夠幫助到您:

  • 瞭解您的goroutine如何執行。
  • 瞭解一些核心運行時事件,例如GC運行。
  • 肯定並行化執行不佳。

可是,這對於識別熱點(例如分析過多的內存或CPU使用率的緣由)不是很好。而是首先使用分析工具來解決它們。

tracer-lock.png

上面的go工具跟蹤可視化顯示執行開始良好,而後序列化了。它代表可能存在致使瓶頸的共享資源的鎖爭用。

請參閱go tool trace以收集和分析運行時跟蹤。

GODEBUG

若是相應地設置了GODEBUG環境變量,則運行時還會發出事件和信息。

  • GODEBUG=gctrace=1 在每一個收集時打印垃圾收集器事件,總結收集的內存量和暫停的時間。
  • GODEBUG=schedtrace=X 每X毫秒打印一次調度事件。

GODEBUG環境變量可用於在標準庫和運行時中禁用指令集擴展。

  • GODEBUG=cpu.all=off 禁用全部可選指令集擴展的使用。
  • GODEBUG=cpu.extension=off 禁止使用指定指令集擴展中的指令。 擴展名是指令集擴展名的小寫名稱,例如sse41或avx。
相關文章
相關標籤/搜索