Golang 監(jiān)控全局變量

前言

你是否曾經(jīng)遇到過這樣的情況,在開發(fā)環(huán)境排查問題,因為一些數(shù)據(jù)保存在了一些全局變量中,這些變量往往是一個 map 或者是一個數(shù)組,想看看在運行過程中,這里面究竟存放了什么數(shù)據(jù),有時不得不在運行的時候?qū)⑺敵龅饺罩局校敲慈绻蚁雽崟r看到這些數(shù)據(jù)的情況又怎么辦呢?

其實 golang 中已經(jīng)存在這樣的庫,就是來做這個事情的 expvar

使用案例

廢話不多數(shù),直接上案例

package main

import (
    "expvar"
    "net/http"
)

var (
    s    map[string]string
    user User
)

type User struct {
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func showMap() interface{} {
    return s
}

func showUser() interface{} {
    return user
}

func main() {
    user.Name = "tom"
    user.Age = 18
    s = make(map[string]string, 10)
    s["1"] = "111"
    s["2"] = "222"
    expvar.Publish("a_map", expvar.Func(showMap))
    expvar.Publish("b_user", expvar.Func(showUser))
    http.HandleFunc("/test", func(writer http.ResponseWriter, request *http.Request) {
        s["3"] = "333"
    })
    http.ListenAndServe(":8080", nil)
}

監(jiān)控變量

直接訪問 http://127.0.0.1:8080/debug/vars 你就能看到一個 json 格式的返回數(shù)據(jù),數(shù)據(jù)如下所示:

{
  "a_map": {
    "1": "111",
    "2": "222"
  },
  "b_user": {
    "name": "tom",
    "age": 18
  },
  "cmdline": [
    "/private/var/folders/37/qpz6_ndd1w72bhrg2sgg042r0000gn/T/___go_build_go_demo_vars"
  ],
  "memstats": {
    "Alloc": 188992,
    "TotalAlloc": 188992,
    "Sys": 70453248,
    "Lookups": 0,
    "Mallocs": 818,
    "Frees": 21,
    "HeapAlloc": 188992,
    "HeapSys": 66650112,
    "HeapIdle": 65716224,
    "HeapInuse": 933888,
    "HeapReleased": 65683456,
    "HeapObjects": 797,
    "StackInuse": 458752,
    "StackSys": 458752,
    "MSpanInuse": 15776,
    "MSpanSys": 16384,
    "MCacheInuse": 6944,
    "MCacheSys": 16384,
    "BuckHashSys": 2638,
    "GCSys": 2240512,
    "OtherSys": 1068466,
    "NextGC": 4473924,
    "LastGC": 0,
    "PauseTotalNs": 0,
    ......
  }
}

這里面一方面將你的在代碼中全局變量顯示了出來還有個 cmdlinememstats 這個我們后面再說

這是你可以訪問一次 http://127.0.0.1:8080/test 然后再回來看看,就會發(fā)現(xiàn)變量的值以及改變,說明這個變量顯示的是實時的

監(jiān)控原理

其實原理非常簡單,你自己都能寫,下面就是源碼中的一部分

// Handler returns the expvar HTTP Handler.
//
// This is only needed to install the handler in a non-standard location.
func Handler() http.Handler {
    return http.HandlerFunc(expvarHandler)
}

func cmdline() interface{} {
    return os.Args
}

func memstats() interface{} {
    stats := new(runtime.MemStats)
    runtime.ReadMemStats(stats)
    return *stats
}

func init() {
    http.HandleFunc("/debug/vars", expvarHandler)
    Publish("cmdline", Func(cmdline))
    Publish("memstats", Func(memstats))
}

其實就是在 init 的時候注冊了對應(yīng)的路由,還注冊了 cmdline 和 memstats 兩個值,這兩個值很有用:

  • cmdline 展示了當(dāng)前啟動時通過命令行傳遞的參數(shù)是什么
  • memstats 展示了當(dāng)前運行時內(nèi)存的使用情況,還有 gc 的部分信息等等

其他方法

https://golang.org/pkg/expvar/

當(dāng)然這個包不止有 Publish 方法,還有 Add、Set 等等,個人最常用的還是 Publish

監(jiān)控內(nèi)存并展示

既然 expvar 暴露了內(nèi)存的使用情況,那我們當(dāng)然能利用這個信息來作圖了,所以就推薦一個很好用的庫

https://github.com/rs/jplot

安裝之后,就可以用命令通過之前的接口來監(jiān)控內(nèi)存等使用情況咯

jplot --url http://127.0.0.1:8080/debug/vars \
    memstats.HeapSys+memstats.HeapAlloc+memstats.HeapIdle+marker,counter:memstats.NumGC \
    counter:memstats.TotalAlloc \
    memstats.HeapObjects \
    memstats.StackSys+memstats.StackInuse

我覺得這樣的使用方式在本地和開發(fā)環(huán)境的時候測試更加輕量,不用部署一些監(jiān)控軟件,即開即測;當(dāng)然線上環(huán)境肯定會有 prometheus + grafana 這樣的監(jiān)控神器,這里也只是拋個磚頭。

總結(jié)

如果線上需要監(jiān)控一些全局變量的使用情況可以考慮使用 expvar 進(jìn)行監(jiān)控和查看,或者用它來監(jiān)控你的配置文件或者一些任務(wù)數(shù)量等等也是一個不錯的選擇。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容