在工程中遇到一个问题,pprof通过配置文件的一个开关来决定是否启动pprof端口A;同一个程序还使用net/http启动了另外一个http服务在端口B。
当程序上线以后,配置文件中pprof的开关时关闭的,pprof端口A也没有启动,但做安全扫描的时候,发现在在端口B也发现了/debug/pprof/也可以访问。
经过定位,发现是工程在匿名引用net/http/pprof包的时候,这个包的init函数如下:
func init() {
http.HandleFunc("/debug/pprof/", Index)
http.HandleFunc("/debug/pprof/cmdline", Cmdline)
http.HandleFunc("/debug/pprof/profile", Profile)
http.HandleFunc("/debug/pprof/symbol", Symbol)
http.HandleFunc("/debug/pprof/trace", Trace)
}
这里会在每个net/http启动的http服务里面注入pprof相关的服务。
为此,我专门写了一段测试代码,如下
package main
import (
"fmt"
"github.com/gin-contrib/cors"
"github.com/gin-gonic/gin"
"net/http"
_ "net/http/pprof"
"os"
"time"
)
func main() {
stopChan := make(chan struct{}, 1)
go http.ListenAndServe("0.0.0.0:9999", nil)
http.HandleFunc("/status", func(writer http.ResponseWriter, request *http.Request) {
fmt.Fprintf(writer, "alive")
})
go func() {
err := http.ListenAndServe(":8999", nil)
if err != nil {
fmt.Println("Http服务启动失败:" + err.Error())
os.Exit(1)
} else {
fmt.Println("Http服务启动成功")
}
}()
r := gin.Default()
//支持跨域
r.Use(cors.Default())
root := r.Group("/")
root.GET("/status", func(context *gin.Context) {
context.String(http.StatusOK, "alive")
//context.JSON(http.StatusOK, "OK")
})
srv := &http.Server{
Addr: "0.0.0.0:7999",
Handler: r,
ReadTimeout: 3 * time.Second,
WriteTimeout: 3 * time.Second,
}
srv.ListenAndServe()
<-stopChan
}
经测试,在9999和8999端口上,都能够访问/debug/pprof/,当然也同时可以访问/status。意思就是如果你用net/http启动多个服务,那每个服务下面的uri都是可以在所有端口上访问的。
但是通过gin启动的则不受影响。