使用 Gorilla 的 mux 与 net/http/pprof 构建的 Profiling Go Web 应用程序



我有一个用 Go 编写的相对较大的 Web 应用程序,它使用 Gorilla 的 mux 进行路由。 我最近意识到我的 Web 应用程序非常慢,我想分析 Web 应用程序。

看完之后,似乎net/http/pprof就是我需要的。 但我不能让它用复用器运行;即使在最微不足道的 Web 应用程序的情况下。

有谁知道如何做到这一点?

这是一个不起作用的琐碎代码的示例(即/debug不提供任何内容)。

package main
import (
    "fmt"
    "github.com/gorilla/mux"
    "math"
    "net/http"
)
import _ "net/http/pprof"
func SayHello(w http.ResponseWriter, r *http.Request) {
    for i := 0; i < 1000000; i++ {
        math.Pow(36, 89)
    }
    fmt.Fprint(w, "Hello!")
}
func main() {
    r := mux.NewRouter()
    r.HandleFunc("/hello", SayHello)
    http.ListenAndServe(":6060", r)
}

我的首选方法是让net/http/pprof将自己注册到 http.DefaultServeMux ,然后传递以 /debug/pprof/ 开头的所有请求:

package main
import (
    "net/http"
    _ "net/http/pprof"
    "github.com/gorilla/mux"
)
func main() {
    router := mux.NewRouter()
    router.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux)
    if err := http.ListenAndServe(":6060", router); err != nil {
        panic(err)
    }
}

我发现这种方法比依赖于隐藏初始化方法的实现的方法稳定得多,并且还可以保证您不会错过任何内容。

user983716 - 感谢您的问题和解决方案!

我无法使用 Web 索引 (http://[my-server]/debug/pprof) 中的链接,直到我在您的解决方案中添加了几行,如下所示:

...
func AttachProfiler(router *mux.Router) {
    router.HandleFunc("/debug/pprof/", pprof.Index)
    router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
    router.HandleFunc("/debug/pprof/profile", pprof.Profile)
    router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
    // Manually add support for paths linked to by index page at /debug/pprof/
    router.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
    router.Handle("/debug/pprof/heap", pprof.Handler("heap"))
    router.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
    router.Handle("/debug/pprof/block", pprof.Handler("block"))
}
...

如果有人有同样的问题,我希望这有所帮助!

对不起这个问题。 答案就在 pprof 的 init() 函数中。 只需将 4 个功能从 pprof 添加到多路复用路由器。 这是上面的固定代码。

package main
import (
    "fmt"
    "github.com/gorilla/mux"
    "math"
    "net/http"
)
import "net/http/pprof"
func AttachProfiler(router *mux.Router) {
    router.HandleFunc("/debug/pprof/", pprof.Index)
    router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
    router.HandleFunc("/debug/pprof/profile", pprof.Profile)
    router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
}
func SayHello(w http.ResponseWriter, r *http.Request) {
    for i := 0; i < 1000000; i++ {
        math.Pow(36, 89)
    }
    fmt.Fprint(w, "Hello!")
}
func main() {
    r := mux.NewRouter()
    AttachProfiler(r)
    r.HandleFunc("/hello", SayHello)
    http.ListenAndServe(":6060", r)
}

我做了别的事情,我在不同的端口上添加了另一个本机http服务器,它开箱即用

package main
import (
    "fmt"
    "log"
    "net/http"
    _ "net/http/pprof"
)

func main() {
    go func() {
        log.Println(http.ListenAndServe(":6060", nil))
    }()
    log.Fatalln(http.ListenAndServe(":8080", route.Handlers()))
}

现在 pprof 端点位于: http://localhost:6060/debug/pprof/并且应用程序在端口上运行:8080

以前的例子对我这边并不真正有效。

要在现有的 golang 项目中使用 pprof 和 gorrila/mux,请尝试添加:

...previous code
func main() {
    r := mux.NewRouter()
    r.HandleFunc("/hello", SayHello)
    go func() {
        log.Fatal(http.ListenAndServe(":6061", http.DefaultServeMux))
    }()
    http.ListenAndServe(":6060", r)
}

然后转到 http://localhost:6061/debug/pprof/

就是这样:

r := mux.NewRouter()
r.PathPrefix("/debug").Handler(http.DefaultServeMux)

我使用 https://github.com/julienschmidt/httprouter 但我刚刚从谷歌搜索中得到了这个答案。这就是我所做的

router := httprouter.New()
router.Handler("GET", "/debug/pprof/profile", http.DefaultServeMux)
router.Handler("GET", "/debug/pprof/heap", http.DefaultServeMux)

我只需要这两条路线。这个答案是@damien和@user983716答案的结合。

以下方法应该有效:

import (
 "net/http"
 _ "net/http/pprof"
)
myrouter.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux)

最新更新