avatar

go开启pporf, 通过webui对服务进行诊断


go作为现代高级编程语言,无须程序员关心内存申请和释放,降低了入门门槛,但也导致很多水平良莠不齐的人写出很多不好的代码,导致服务出现各种各样不稳定的情况。如大对象的频繁申请和释放、协程泄露、指针断言反射的乱用等等。
虽然说代码是屎山,但是在服务尚且能用的情况下,架构师肯定没有精力来调教每行代码,这时候就可以通过pprof从宏观层面把脉服务的运行情况,从而找出那些脑残的代码来优化。

无论是用gin,还是go-zero, 亦或者net/http, 接入pprof都十分简单,只需要将pprof的几个handle函数注册到web框架的route里面即可,我们以go-zero为例

先定义一个profile.go文件

 1package profile
 2
 3import (
 4	"github.com/zeromicro/go-zero/rest"
 5	"net/http"
 6	"net/http/pprof"
 7)
 8
 9func wrapH(h http.Handler) http.HandlerFunc {
10	return func(ResponseWriter http.ResponseWriter, Request *http.Request) {
11		h.ServeHTTP(ResponseWriter, Request)
12	}
13}
14
15func ProfileRoutes() []rest.Route {
16	pprofRoutes := make([]rest.Route, 0)
17	pprofRoutes = append(pprofRoutes, rest.Route{
18		Method:  http.MethodGet,
19		Path:    "/debug/pprof/",
20		Handler: pprof.Index,
21	})
22	pprofRoutes = append(pprofRoutes, rest.Route{
23		Method:  http.MethodGet,
24		Path:    "/debug/pprof/cmdline",
25		Handler: pprof.Cmdline,
26	})
27	pprofRoutes = append(pprofRoutes, rest.Route{
28		Method:  http.MethodGet,
29		Path:    "/debug/pprof/profile",
30		Handler: pprof.Profile,
31	})
32	pprofRoutes = append(pprofRoutes, rest.Route{
33		Method:  http.MethodGet,
34		Path:    "/debug/pprof/symbol",
35		Handler: pprof.Symbol,
36	})
37	pprofRoutes = append(pprofRoutes, rest.Route{
38		Method:  http.MethodPost,
39		Path:    "/debug/pprof/symbol",
40		Handler: pprof.Symbol,
41	})
42	pprofRoutes = append(pprofRoutes, rest.Route{
43		Method:  http.MethodGet,
44		Path:    "/debug/pprof/trace",
45		Handler: pprof.Trace,
46	})
47	pprofRoutes = append(pprofRoutes, rest.Route{
48		Method:  http.MethodGet,
49		Path:    "/debug/pprof/goroutine",
50		Handler: wrapH(pprof.Handler("goroutine")),
51	})
52	pprofRoutes = append(pprofRoutes, rest.Route{
53		Method:  http.MethodGet,
54		Path:    "/debug/pprof/heap",
55		Handler: wrapH(pprof.Handler("heap")),
56	})
57	pprofRoutes = append(pprofRoutes, rest.Route{
58		Method:  http.MethodGet,
59		Path:    "/debug/pprof/block",
60		Handler: wrapH(pprof.Handler("block")),
61	})
62	pprofRoutes = append(pprofRoutes, rest.Route{
63		Method:  http.MethodGet,
64		Path:    "/debug/pprof/mutex",
65		Handler: wrapH(pprof.Handler("mutex")),
66	})
67	pprofRoutes = append(pprofRoutes, rest.Route{
68		Method:  http.MethodGet,
69		Path:    "/debug/pprof/threadcreate",
70		Handler: wrapH(pprof.Handler("threadcreate")),
71	})
72	pprofRoutes = append(pprofRoutes, rest.Route{
73		Method:  http.MethodGet,
74		Path:    "/debug/pprof/allocs",
75		Handler: wrapH(pprof.Handler("allocs")),
76	})
77
78	return pprofRoutes
79}

之后在main中将这些routes加到server里面

 1func main() {
 2	...
 3
 4	server := rest.MustNewServer(restConf)
 5	defer server.Stop()
 6
 7	gen.Register(server)
 8
 9
10	// profile 性能分析
11	server.AddRoutes(profile.ProfileRoutes(), rest.WithTimeout(time.Second*35))
12
13	server.Start()
14}

这样程序启动之后就可以通过go tool pprof命令去在浏览器中查看服务的cpu、堆栈、协程的运行情况。

1go tool pprof -http=:1234 http://$server_ip:$server_port/debug/pprof/allocs

请确保自己的机器装了graphviz,这样就可以在浏览器中以图的方式来快速定位问题,以macos为例:

1brew install graphviz

内存

内存

评论列表:

暂无评论 😭