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