你喜歡的 Go 第三方庫:一步為系統(tǒng)集成可視化實時運行時統(tǒng)計
大家好,我是站長 polarisxu。
掌握系統(tǒng)運行狀態(tài),知道系統(tǒng)哪些地方可能存在問題,方便進(jìn)行優(yōu)化,這是一個實際系統(tǒng)必備的。裸奔,對系統(tǒng)一無所知,遲早是要出大事的。
在 Go 語言中,官方標(biāo)準(zhǔn)庫提供了方法,讓我們能夠獲得內(nèi)存分配、GC 和 Goroutine 等情況。比如內(nèi)存、GC 等情況,可以通過 runtime.MemStats 獲取:https://docs.studygolang.com/pkg/runtime/#MemStats,Goroutine 數(shù)量可以通過 runtime.NumGoroutine() 函數(shù)獲得。
一般我們我們需要自己解析 MemStats 信息、做展示,也可以做圖表。
今天我給大家推薦一個庫:https://github.com/arl/statsviz,它是一個在瀏覽器中實時查看 Go 應(yīng)用程序運行時統(tǒng)計信息(GC,MemStats 等)的庫。
它能展示的信息如下圖:
再看其中 Heap 的實時動圖:
上面這些通過運行下面這段代碼就可以了:
- package main
- import (
- "math/rand"
- "net/http"
- "strconv"
- "time"
- "github.com/arl/statsviz"
- )
- func main() {
- // Force the GC to work to make the plots "move".
- go work()
- // Register statsviz handlers on the default serve mux.
- statsviz.RegisterDefault()
- http.ListenAndServe(":8080", nil)
- }
- func work() {
- // Generate some allocations
- m := map[string][]byte{}
- for {
- b := make([]byte, 512+rand.Intn(16*1024))
- m[strconv.Itoa(len(m)%(10*100))] = b
- if len(m)%(10*100) == 0 {
- m = make(map[string][]byte)
- }
- time.Sleep(10 * time.Millisecond)
- }
- }
1、如何使用
都 Go1.15.x 了,請使用 go module。
statsviz 的使用很簡單。假設(shè)基于 net/http 使用。
- import "github.com/arl/statsviz”
- 注冊 statsviz HTTP handlers
- 啟動程序
- 打開瀏覽器訪問:http://host:port/debug/statsviz
- 盡情享受吧~
具體看看實際中怎么集成到項目中,根據(jù)可能的情況分別介紹。
基于 net/http
如果你的項目沒有使用框架,直接基于 net/http;或者你的項目并沒有提供 HTTP 服務(wù)。集成 statsviz 可以按照下面的方式。
1)一個使用 net/http 的 Web 項目
只需要 import statsviz 包后,在注冊路由的地方加上如下代碼:
- statsviz.RegisterDefault()
這是使用默認(rèn)的 http.DefaultServeMux,如果你使用的是自定義 Mux,則加上如下類似如下代碼:
- mux := http.NewServeMux()
- statsviz.Register(mux)
其中,mux 使用你定義好的。
實際上,statsviz.RegisterDefault() 內(nèi)部是這么實現(xiàn)的:
- func RegisterDefault() {
- Register(http.DefaultServeMux)
- }
2)沒有提供 HTTP 服務(wù)的項目
這時最簡單的方式就是使用 statsviz.RegisterDefault() ,同時需要啟動一個 HTTP 服務(wù):
- go func() {
- statsviz.RegisterDefault()
- log.Println(http.ListenAndServe("localhost:8080", nil))
- }()
基于兼容 net/http 的框架
因為兼容 net/http 框架,因此可以直接將 statsviz 的 Handler 集成進(jìn)去。比如對于 gorilla/mux 庫,可以這么做:
- r := mux.NewRouter()
- r.Methods("GET").Path("/debug/statsviz/ws").Name("GET /debug/statsviz/ws").HandlerFunc(statsviz.Ws)
- r.Methods("GET").PathPrefix("/debug/statsviz/").Name("GET /debug/statsviz/").Handler(statsviz.Index)
- mux := http.NewServeMux()
- mux.Handle("/", r)
- http.ListenAndServe(":8080", mux)
這里主要是 statsviz.Ws 和 statsviz.Index,因為 gorilla/mux 庫兼容 net/http,所以可以這么做。
不兼容 net/http 的框架
比如集成進(jìn) Gin 框架。做法就是和“沒有提供 HTTP 服務(wù)的項目”一樣,另開一個 HTTP 端口。
- go func() {
- statsviz.RegisterDefault()
- log.Println(http.ListenAndServe("localhost:8080", nil))
- }()
因此這里實際上和具體框架沒關(guān)系。
最佳實踐
因為 runtime 信息屬于系統(tǒng)內(nèi)部信息,不適合暴露給公網(wǎng)用戶。因此,實際上中,最佳實踐是,不管什么情況下,都單獨開一個 HTTP 端口,類似下面這樣,對公網(wǎng)不可訪問。
- go func() {
- statsviz.RegisterDefault()
- log.Println(http.ListenAndServe("localhost:8080", nil))
- }()
原理簡單說明
該庫使用 WebSocket 協(xié)議,定時將系統(tǒng)的 runtime 數(shù)據(jù)發(fā)送給瀏覽器,瀏覽器接收到之后,利用 JS 繪制圖表,展示出來。Go 核心代碼如下:
- // sendStats indefinitely send runtime statistics on the websocket connection.
- func sendStats(conn *websocket.Conn) error {
- tick := time.NewTicker(defaultSendPeriod)
- defer tick.Stop()
- var stats stats
- for {
- select {
- case <-tick.C:
- runtime.ReadMemStats(&stats.Mem)
- stats.NumGoroutine = runtime.NumGoroutine()
- if err := conn.WriteJSON(stats); err != nil {
- return err
- }
- }
- }
- }
對客戶端代碼感興趣的請自行閱讀源碼。
總結(jié)
如果你需要實時圖表的方式查看系統(tǒng)運行時的一些數(shù)據(jù),可以嘗試下它。用類似這樣幾行代碼一步將它集成進(jìn)你的系統(tǒng):
- go func() {
- statsviz.RegisterDefault()
- log.Println(http.ListenAndServe("localhost:8080", nil))
- }()