【问题标题】:Profiling Go web application built with Gorilla's mux with net/http/pprof使用 Gorilla 的 mux 和 net/http/pprof 分析 Go Web 应用程序
【发布时间】:2019-10-22 11:33:30
【问题描述】:

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

阅读后,似乎net/http/pprof 是我需要的。但我不能让它与 mux 一起运行;即使是最简单的 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)
}

【问题讨论】:

    标签: go


    【解决方案1】:

    我的首选方法是让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)
        }
    }
    

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

    【讨论】:

    • 我们应该知道/debug/pprof/路由不应该在生产环境中公开,因为它可能会暴露敏感数据。请参阅以下文章中的建议,其中禁用了默认多路复用路由,并且您仅公开 pprof 以进行 localhost 访问:docs.boostsecurity.io/rules/…
    【解决方案2】:

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

    我无法使用网络索引 (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"))
    }
    
    ...
    

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

    【讨论】:

    • 我刚刚做了router.PathPrefix("/debug/pprof/").HandlerFunc(pprof.Index),它涵盖了所有未明确路由的内容。
    【解决方案3】:

    抱歉这个问题。答案在pprof 的init() 函数中。只需将pprof 中的4 个函数添加到多路复用路由器即可。这是上面的固定代码。

    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)
    }
    

    【讨论】:

      【解决方案4】:

      以前的例子对我来说并不适用。

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

      ...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/

      【讨论】:

        【解决方案5】:

        我做了其他事情,我在不同的端口上添加了另一个本机 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 上运行

        【讨论】:

          【解决方案6】:

          就是这样:

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

          【讨论】:

            【解决方案7】:

            我正在使用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 答案的结合。

            【讨论】:

              【解决方案8】:

              以下应该有效:

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

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2014-12-21
                • 2017-06-19
                • 1970-01-01
                • 2015-09-25
                • 2015-05-03
                • 2022-01-20
                • 1970-01-01
                相关资源
                最近更新 更多