Loading

Go语言精进之路读书笔记第48条——使用expvar输出度量数据,辅助定位性能瓶颈点

48.1 expvar包的工作原理

Go标准库中的expvar包提供了一种输出应用内部状态信息的标准化方案,这个方案标准化了以下三方面内容:

  • 数据输出接口形式
  • 输出数据的编码格式
  • 用户自定义性能指标的方法
import (
    _ "expvar"
    "fmt"
    "net/http"
)

func main() {
    http.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hi"))
    }))
    fmt.Println(http.ListenAndServe("localhost:8080", nil))
}

手动注册路由

func main() {
    mux := http.NewServeMux()
    mux.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hi"))
    }))
    mux.Handle("/debug/vars", expvar.Handler())
    fmt.Println(http.ListenAndServe("localhost:8080", mux))
}

48.2 自定义应用通过expvar输出的度量数据

1.用户自定义性能指标的方法

type CustomVar struct {
    value int64
}

func (v *CustomVar) String() string {
    return strconv.FormatInt(atomic.LoadInt64(&v.value), 10)
}

func (v *CustomVar) Add(delta int64) {
    atomic.AddInt64(&v.value, delta)
}

func (v *CustomVar) Set(value int64) {
    atomic.StoreInt64(&v.value, value)
}

func init() {
    customVar := &CustomVar{
        value: 17,
    }
    expvar.Publish("customVar", customVar)

}

func main() {
    http.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hi"))
    }))
    fmt.Println(http.ListenAndServe("localhost:8080", nil))
}

2.将customVar指标改为使用expvar.Int实现

var customVar *expvar.Int

func init() {
    customVar = expvar.NewInt("customVar")
    customVar.Set(17)
}

func main() {
    http.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hi"))
    }))

    // 模拟业务逻辑
    go func() {
        //... ...
        for {
            customVar.Add(1)
            time.Sleep(time.Second)
        }
    }()

    fmt.Println(http.ListenAndServe("localhost:8080", nil))
}

3.使用expvar.Map类型

var customVar *expvar.Map

func init() {
    customVar = expvar.NewMap("customVar")

    var field1 expvar.Int
    var field2 expvar.Float
    customVar.Set("field1", &field1)
    customVar.Set("field2", &field2)
}

func main() {
    http.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hi"))
    }))

    // 模拟业务逻辑
    go func() {
        //... ...
        for {
            customVar.Add("field1", 1)
            customVar.AddFloat("field2", 0.001)
            time.Sleep(time.Second)
        }
    }()

    fmt.Println(http.ListenAndServe("localhost:8080", nil))
}

4.使用结构体类型

type CustomVar struct {
    Field1 int64   `json:"field1"`
    Field2 float64 `json:"field2"`
}

var (
    field1 expvar.Int
    field2 expvar.Float
)

func exportStruct() interface{} {
    return CustomVar{
        Field1: field1.Value(),
        Field2: field2.Value(),
    }
}

func init() {
    expvar.Publish("customVar", expvar.Func(exportStruct))
}

func main() {
    http.Handle("/hi", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("hi"))
    }))

    // 模拟业务逻辑
    go func() {
        //... ...
        for {
            field1.Add(1)
            field2.Add(0.001)
            time.Sleep(time.Second)
        }
    }()

    fmt.Println(http.ListenAndServe("localhost:8080", nil))
}

48.3 输出数据的展示

  • 通过/debug/vars服务端点,我们可以得到标准JSON格式的应用内部状态数据
  • 开源工具(终端图形化):expvarmon
posted @ 2024-03-10 20:17  brynchen  阅读(35)  评论(0编辑  收藏  举报