golang做为一种自带gc(garbage collection)回收机制的语言,往往可能会给人一种错觉,用golang写的程序一般不会存在内存泄漏(因为golang自带的GC会将不用的内存回收掉),实则不然。在实际开发的过程中,出现最多的一种情况是goroutine泄漏造成的内存泄漏,这里重点说怎么排查roroutine泄漏。由于公司对云服务部署的软件有严格的安全要求,直接使用net/http/pprof模块,可能会有安全方面的漏洞,这里先说下怎么在公网使用pprof规避安全漏洞:
// Copyright 2010 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Package pprof serves via its HTTP server runtime profiling data // in the format expected by the pprof visualization tool. // // The package is typically only imported for the side effect of // registering its HTTP handlers. // The handled paths all begin with /debug/pprof/. // // To use pprof, link this package into your program: // import _ "net/http/pprof" // // If your application is not already running an http server, you // need to start one. Add "net/http" and "log" to your imports and // the following code to your main function: // // go func() { // log.Println(http.ListenAndServe("localhost:6060", nil)) // }() // // If you are not using DefaultServeMux, you will have to register handlers // with the mux you are using. // // Then use the pprof tool to look at the heap profile: // // go tool pprof http://localhost:6060/debug/pprof/heap 正如net/http/pprof/pprof.go中上面我标准红色字体的所说,不指定http的mux,则pprof会使用默认的DefaultServerMux,如果其他做业务的HTTP也没有使用自己的mux,则使用的也是DefaultServerMux,这样及时pprof监听的IP地址是127.0.0.1,也可能存在安全漏洞,示例如下:
pprof监听的IP地址和端口: go func() { pprofHttp.ListenAndServe("localhost:50000", nil) }()
真正做业务的HTTP服务监听的接口和端口:
func HelloHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello World") } func main () { http.HandleFunc("/", HelloHandler) http.ListenAndServe(":8000", nil) }
假设该软件部署的公网IP地址为:49.215.92.3
则在浏览器上输入:https://49.215.92.3/debug/pprof/,就会看到程序对应的各种信息,比如:所有的goroutine等堆栈信息。公司的安全扫描软件扫到,就会找到你,让你修复这个安全漏洞(如果有些公司对安全不重视,可以忽略该问题)。
要些解决解决这个漏洞,可以将做业务的Http接口改为:
func HelloHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello World") } func main () { mux := http.NewServeMux() mux.handle("/", http.HandleFunc(HelloHandler)) http.ListenAndServe(":8000", nil) }
这样在浏览器上输入:https://49.215.92.3/debug/pprof/,会提示404,安全漏洞得以解决:
排查goroutine泄漏可以在服务器后台使用命令行:
curl http://localhost:50000/debug/pprof/goroutine?debug=2 > xxxGoroutine.out,这样所有的goroutine堆栈信息都会写到.out文件中,看看那些goroutine阻塞的时间比较长,再结合业务,就会查找到有哪些goroutine泄漏。