-
Notifications
You must be signed in to change notification settings - Fork 0
go_profile
Xiaolin Zhang edited this page Nov 2, 2019
·
1 revision
一直对性能优化感兴趣, 但是没有入手的点, 转到GO之后, 这些就不是问题了.
Go 提供两个工具, 一个在net包下, 一个在pprof包下, net包通过启动一个网络服务, 对外暴露你程序信息, 而pprof提供一种编程的方式, 从你指定时间开始到指定时间结束, 把信息记录到一个writer中.
现在可以获得一个交互式的前端页面, 不需要下面那么繁琐去获得火焰图
go tool pprof -http=:8080 profile_10.10.73.173_20181206-070730.pb.gz
具体实现我没看过, 但是猜一下, 应该是通过采样的方式给cpu快照, 读取寄存器的状态,
快照这一点很重要, 尤其是一个大型web服务, 必须通过压测才能准确的记录下来, cpu执行的代码, 否者看到的都是runtime的一些方法.
func Handler(meta endpoint.Meta, next endpoint.Endpoint) endpoint.Endpoint {
profMapLock.Lock()
defer profMapLock.Unlock()
traceBytes := []byte{}
tracePtr := &traceBytes
var lock sync.Mutex
var buf bytes.Buffer
var traceBuf bytes.Buffer
var hasMerged bool
setEnabled()
// Prepare buffers for this endpoint
merged := new(profile.Profile)
profKey := meta.Service + "." + meta.Name
profMap[profKey] = &profileDump{
profile: merged,
trace: tracePtr,
}
profWriter := bufio.NewWriter(&buf)
traceWriter := bufio.NewWriter(&traceBuf)
return func(ctx context.Context, request interface{}) (metadata metadata.Metadata, response interface{}, err error) {
// Lock to ensure only one endpoint is profiled at a time
lock.Lock()
defer lock.Unlock()
// Profile just this endpoint
if err := pprof.StartCPUProfile(profWriter); err != nil {
// If already enabled, don't profile
return next(ctx, request)
}
if err := trace.Start(traceWriter); err != nil {
// If already enabled, don't trace
return next(ctx, request)
}
metadata, response, err = next(ctx, request)
trace.Stop()
_ = traceWriter.Flush()
pprof.StopCPUProfile()
_ = profWriter.Flush()
*tracePtr = traceBuf.Bytes()
// Parse and merge profiles ready for converting to flamegraph
// This is done eagerly but could be deferred until the flamegraph is called
thisProf, parseErr := profile.Parse(bufio.NewReader(&buf))
buf.Reset()
traceBuf.Reset()
if parseErr == nil {
if hasMerged {
m, merr := profile.Merge([]*profile.Profile{merged, thisProf})
if merr == nil {
*merged = *m
}
return
}
*merged = *thisProf
hasMerged = true
}
return
}
}
上面是一个middleware实现, 最终cpu信息会记录到profMap中. (要多次调用接口才能看到效果).
1.首先,我们要配置FlameGraph
的脚本
FlameGraph 是profile数据的可视化层工具,已被广泛用于Python和Node
git clone https://github.com/brendangregg/FlameGraph.git
2.检出完成后,把flamegraph.pl
拷到我们机器环境变量$PATH的路径中去
3.在终端输入 flamegraph.pl -h
是否安装FlameGraph成功
诸如flamegraph.pl是pl写的分析脚本, 就是用来生成火焰图的, 在调用他之前, 还要用stackcollapse-go.pl专门处理一下Go语言的数据.
go-touch提供更方便的方式, 直接可以将cpu.prof转化成火焰图