GoFrame框架的Web Server提供了非常强大和简便的服务性能分析功能,内部完美集成了pprof性能分析工具,可以在任何时候通过EnablePProf方法启用性能分析特性,并可自定义性能分析工具页面路由地址,不传递路由地址时,默认URI地址为/debug/pprof

PProf启用

PProf特性的启用会对程序性能产生一定影响,具体影响程度需要根据当前业务场景在PProd启用前后进行对比。

EnablePProf

我们来看一个简单的例子:

  1. package main
  2. import (
  3. "github.com/gogf/gf/v2/frame/g"
  4. "github.com/gogf/gf/v2/net/ghttp"
  5. "runtime"
  6. )
  7. func main() {
  8. runtime.SetMutexProfileFraction(1) // (非必需)开启对锁调用的跟踪
  9. runtime.SetBlockProfileRate(1) // (非必需)开启对阻塞操作的跟踪
  10. s := g.Server()
  11. s.EnablePProf()
  12. s.BindHandler("/", func(r *ghttp.Request) {
  13. r.Response.Writeln("哈喽世界!")
  14. })
  15. s.SetPort(8199)
  16. s.Run()
  17. }

这个例子使用了s.EnablePProf()启用了性能分析,默认会自动注册以下几个路由规则:

  1. /debug/pprof/*action
  2. /debug/pprof/cmdline
  3. /debug/pprof/profile
  4. /debug/pprof/symbol
  5. /debug/pprof/trace

其中/debug/pprof/*action为页面访问的路由,其他几个地址为go tool pprof命令准备的。

StartPProfServer

也可以使用StartPProfServer方法,快速开启一个独立的PProf Server,常用于一些没有HTTP Server的常驻的进程中(例如定时任务、GRPC服务中),可以快速开启一个PProf Server用于程序性能分析。该方法的定义如下:

  1. func StartPProfServer(port int, pattern ...string)

一般的场景是使用异步goroutine运行该PProd Server,即往往是这么来使用:

  1. package main
  2. import (
  3. "github.com/gogf/gf/v2/net/ghttp"
  4. )
  5. func main() {
  6. go ghttp.StartPProfServer(8199)
  7. // 其他服务启动、运行
  8. // ...
  9. }

以上示例可以改进为:

  1. package main
  2. import (
  3. "github.com/gogf/gf/v2/frame/g"
  4. "github.com/gogf/gf/v2/net/ghttp"
  5. )
  6. func main() {
  7. go ghttp.StartPProfServer(8299)
  8. s := g.Server()
  9. s.EnablePProf()
  10. s.BindHandler("/", func(r *ghttp.Request) {
  11. r.Response.Writeln("哈喽世界!")
  12. })
  13. s.SetPort(8199)
  14. s.Run()
  15. }

PProf指标

  • heap: 报告内存分配样本;用于监视当前和历史内存使用情况,并检查内存泄漏。
  • threadcreate: 报告了导致创建新OS线程的程序部分。
  • goroutine: 报告所有当前goroutine的堆栈跟踪。
  • block: 显示goroutine在哪里阻塞同步原语(包括计时器通道)的等待。默认情况下未启用,需要手动调用runtime.SetBlockProfileRate启用。
  • mutex: 报告锁竞争。默认情况下未启用,需要手动调用runtime.SetMutexProfileFraction启用。

PProf页面

简单的性能分析我们直接访问/debug/pprof地址即可,内容如下:

1、pprof页面

PProf服务性能分析 - 图1

2、堆使用量

PProf服务性能分析 - 图2

3、当前进程中的goroutine详情

PProf服务性能分析 - 图3

性能采集分析

如果想要进行详细的性能分析,基本上离不开go tool pprof命令行工具的支持,在开启性能分析支持后,我们可以使用以下命令执行性能采集分析:

  1. go tool pprof "http://127.0.0.1:8199/debug/pprof/profile"

执行后pprof工具经过约30秒左右的接口信息采集(这30秒期间WebServer应当有流量进入,我们这里不停地访问hello world页面以作测试),然后生成性能分析报告,随后可以通过top10/web等pprof命令查看报告结果,更多命令可使用go tool pprof查看。关于pprof的详细使用介绍,请查看Golang官方:blog.golang.org/profiling-go-programs

CPU性能分析

本示例中的命令行性能分析结果如下:

  1. $ go tool pprof "http://127.0.0.1:8199/debug/pprof/profile"
  2. Fetching profile over HTTP from http://127.0.0.1:8199/debug/pprof/profile
  3. Saved profile in /home/john/pprof/pprof.___go_build_pprof_go.samples.cpu.001.pb.gz
  4. File: ___go_build_pprof_go
  5. Type: cpu
  6. Time: Apr 17, 2018 at 10:53pm (CST)
  7. Duration: 30s, Total samples = 80ms ( 0.27%)
  8. Entering interactive mode (type "help" for commands, "o" for options)
  9. (pprof) top10
  10. Showing nodes accounting for 80ms, 100% of 80ms total
  11. Showing top 10 nodes out of 49
  12. flat flat% sum% cum cum%
  13. 10ms 12.50% 12.50% 10ms 12.50% github.com/gogf/gf/v2/net/ghttp.(*Cookie).Get /home/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/net/ghttp/http_server_cookie.go
  14. 10ms 12.50% 25.00% 10ms 12.50% internal/poll.runtime_pollReset /home/john/Softs/go1.9.2/src/runtime/netpoll.go
  15. 10ms 12.50% 37.50% 10ms 12.50% runtime.futex /home/john/Softs/go1.9.2/src/runtime/sys_linux_amd64.s
  16. 10ms 12.50% 50.00% 10ms 12.50% runtime.getitab /home/john/Softs/go1.9.2/src/runtime/iface.go
  17. 10ms 12.50% 62.50% 10ms 12.50% runtime.newarray /home/john/Softs/go1.9.2/src/runtime/slice.go
  18. 10ms 12.50% 75.00% 10ms 12.50% runtime.rawstringtmp /home/john/Softs/go1.9.2/src/runtime/string.go
  19. 10ms 12.50% 87.50% 10ms 12.50% runtime.usleep /home/john/Softs/go1.9.2/src/runtime/sys_linux_amd64.s
  20. 10ms 12.50% 100% 10ms 12.50% sync.(*RWMutex).Lock /home/john/Softs/go1.9.2/src/sync/rwmutex.go
  21. 0 0% 100% 10ms 12.50% bufio.(*Writer).Flush /home/john/Softs/go1.9.2/src/bufio/bufio.go
  22. 0 0% 100% 10ms 12.50% github.com/gogf/gf/v2/container/gqueue.(*Queue).PopFront /home/john/Workspace/Go/GOPATH/src/github.com/gogf/gf/v2/container/gqueue/gqueue.go
  23. (pprof) web
  24. Failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in $PATH
  25. (pprof) web
  26. (pprof)

其中web命令用以图形展示接口之间的调用关系以及性能情况,但是需要安装Graphviz图形化工具,以我目前的系统为Ubuntu为例,直接执行sudo apt-get install graphviz命令即可安装完成图形化工具(如果是MacOS,使用brew install Graphviz安装),随后再次使用web命令,最终生成以下图表:

PProf服务性能分析 - 图4

内存使用分析

与CPU性能分析类似,内存使用分析同样使用到go tool pprof命令:

  1. $ go tool pprof http://127.0.0.1:8299/debug/pprof/heap
  2. Fetching profile over HTTP from http://127.0.0.1:8299/debug/pprof/heap
  3. Saved profile in /Users/john/pprof/pprof.alloc_objects.alloc_space.inuse_objects.inuse_space.004.pb.gz
  4. Type: inuse_space
  5. Time: May 24, 2021 at 8:01pm (CST)
  6. Entering interactive mode (type "help" for commands, "o" for options)
  7. (pprof) top
  8. Showing nodes accounting for 1536.39kB, 100% of 1536.39kB total
  9. Showing top 10 nodes out of 19
  10. flat flat% sum% cum cum%
  11. 512.19kB 33.34% 33.34% 512.19kB 33.34% runtime.malg
  12. 512.14kB 33.33% 66.67% 512.14kB 33.33% github.com/gogf/gf/v2/container/gmap.(*StrAnyMap).doSetWithLockCheck
  13. 512.06kB 33.33% 100% 512.06kB 33.33% net.newFD (inline)
  14. 0 0% 100% 512.14kB 33.33% github.com/gogf/gf/v2/container/gmap.(*StrAnyMap).GetOrSetFuncLock
  15. 0 0% 100% 512.06kB 33.33% github.com/gogf/gf/v2/net/ghttp.(*Server).startServer.func1
  16. 0 0% 100% 512.06kB 33.33% github.com/gogf/gf/v2/net/ghttp.(*gracefulServer).ListenAndServe
  17. 0 0% 100% 512.06kB 33.33% github.com/gogf/gf/v2/net/ghttp.(*gracefulServer).doServe
  18. 0 0% 100% 512.14kB 33.33% github.com/gogf/gf/v2/os/gres.Instance
  19. 0 0% 100% 512.14kB 33.33% github.com/gogf/gf/v2/os/gres.init
  20. 0 0% 100% 512.06kB 33.33% net.(*TCPListener).Accept
  21. (pprof) web
  22. (pprof)

通过web图形展示,类似这样的:

PProf服务性能分析 - 图5