文章目录
golang 性能分析
前言
文章主要用于记忆,怕自己忘记,仅供参考
性能分析,一般都是直接运行应用程序分析性能
结合上章
但是线上的web应用程序遇到问题,怎么分析呢,介绍下我自己的方式
1.普通性能分析
一般采集CPU样板数据代码,这里我只写一种,至于其他的内存和trace采集,可以参考:
https://github.com/hyper0x/go_command_tutorial/blob/master/0.12.md
此文章介绍了各种采集样板数据原理,以及展示方式
import (
"runtime/pprof"
"log"
)
func main() {
f, err := os.OpenFile("cpu.out", os.O_RDWR|os.O_CREATE, 0700)
if err != nil {
return
}
defer f.Close()
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
go run main.go,即可看到cpu.out
方法1:
获取cpu分析png图:go tool pprof -png cpu.out > cpu.png
方法二:
进入命令行:go tool pprof cpu.out
top命令:查看cpu和内存消耗排行版
list:查看某个函数的代码,以及该函数每行代码的指标信息,如果函数名不明确,会进行模糊匹配,比如list main会列出main.main
traces:打印所有调用栈,以及调用栈的指标信息
其他命令可以通过help查看
(2). http在线性能分析
网络一般都是默认引入包
“net/http/pprof”
package main
import (
_ "net/http/pprof"
)
这种方式一般适用范围很小,看下pprof默认干了什么?
package pprof
import (
"bufio"
"bytes"
"fmt"
"html/template"
"io"
"log"
"net/http"
"os"
"runtime"
"runtime/pprof"
"runtime/trace"
"strconv"
"strings"
"time"
)
func init() {
http.Handle("/debug/pprof/", http.HandlerFunc(Index))
http.Handle("/debug/pprof/cmdline", http.HandlerFunc(Cmdline))
http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))
http.Handle("/debug/pprof/symbol", http.HandlerFunc(Symbol))
http.Handle("/debug/pprof/trace", http.HandlerFunc(Trace))
}
默认pprof包只是在http对应的handle map数据中,设置了几个handlefunc
但是如果我们程序引入了框架,默认的map数据源可能就失效了
所以我们可以收到把这几个handlefunc,放到我们的框架对应的handle中
这样我们就能在线请求上面的性能分析地址了
总览:线程数量,阻塞调用,内存分析 ,协程分析等
1:文件中的http.Handle("/debug/pprof/", http.HandlerFunc(Index)) 放到handle配置中(此handle包含了所有的分析函数)
2: 浏览器访问http://host:port/debug/pprof/
pprof cpu和内存分析说明
方法1:
1:文件中的http.Handle("/debug/pprof/profile", http.HandlerFunc(Profile))放到handle配置中
3:设置10s收集一次CPU信息:curl 'http//host:port/debug/pprof/profile?seconds=10' -o cpu.out
4:获取cpu分析png图:go tool pprof -png cpu.out > cpu.png
方法二:
1,2跟上面想同
3:进入命令行:go tool pprof cput.out
top命令:查看cpu和内存消耗排行版
list:查看某个函数的代码,以及该函数每行代码的指标信息,如果函数名不明确,会进行模糊匹配,比如list main会列出main.main
traces:打印所有调用栈,以及调用栈的指标信息
help查看其他命令
heap 内存跟踪说明
内存泄露情况:
1:goroutine本身的栈所占用的空间造成内存泄露。
2:goroutine中的变量所占用的堆内存导致堆内存泄露,这一部分是能通过heap profile体现出来的。
内存profiling记录的是堆内存分配的情况,以及调用栈信息,并不是进程完整的内存情况。
栈内存的分配是在调用栈结束后会被释放的内存,所以并不在内存profile中。
因为内存profiling是基于抽样和它跟踪的是已分配的内存,而不是使用中的内存,(比如有些内存已经分配,看似使用,但实际以及不使用的内存,比如内存泄露的那部分),所以不能使用内存profiling衡量程序总体的内存使用情况。
heap能帮助我们发现内存问题,但不一定能发现内存泄露问题,内存主要被哪些代码占用了,程序存在内存问题
1:主要看监控系统:随着时间的推进,内存的占用率在不断的提高,这是内存泄露的最明显现象
2:能够对比两个profile文件的差别,观察
go tool pprof -base heap.out heap2.out
1:设置10s收集一次信息:curl 'http//host:port/debug/pprof/heap?seconds=10' -o heap.out
2:获取heap分析png图:go tool pprof -png heap.out > heap.png
trace 跟踪携程,syscall,垃圾回收说明
1:设置10s收集一次信息:curl 'http//host:port/debug/pprof/trace?seconds=10' -o trace.out
2: 获取trace分析:go tool trace -http="localhost:port" trace.out
5: 访问:http://localhost:port
总结线个人上程序出现502,504先查看CPU的消耗和内存
cpu消耗比较高当然,自己增加服务器
如果cpu和内存消耗都不高的情况下
最大的可能是gc占用时间比较高,这个时候trace信息很有用了,通过访问trace中url
查询traces信息,可以看到主要是哪些对象占用了大量内存,可以从这部分代码入手
根据我的经验,json.unmarshal的时候,采用的是反射原理,默认会简历大量的临时对象
如果json数据包很多,那么会很快产生gc,而golang的gc默认是暂停整个程序运行的,所以
这种情况,要么修改gc条件比如:export GOGC=200,内存增大到3倍,才开始gc
要么减少json反序列化