使用Gorilla的mux和net/http/pprof来对构建的Go Web应用程序进行性能分析。

huangapple go评论107阅读模式
英文:

Profiling Go web application built with Gorilla's mux with net/http/pprof

问题

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

在阅读相关资料后,我发现net/http/pprof是我需要的工具。但是我无法在mux中运行它,即使是在最简单的Web应用程序的情况下也不行。

有人知道如何使其工作吗?

以下是一个不起作用的简单代码示例(即在/debug路径下没有任何内容被提供)。

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gorilla/mux"
  5. "math"
  6. "net/http"
  7. )
  8. import _ "net/http/pprof"
  9. func SayHello(w http.ResponseWriter, r *http.Request) {
  10. for i := 0; i < 1000000; i++ {
  11. math.Pow(36, 89)
  12. }
  13. fmt.Fprint(w, "Hello!")
  14. }
  15. func main() {
  16. r := mux.NewRouter()
  17. r.HandleFunc("/hello", SayHello)
  18. http.ListenAndServe(":6060", r)
  19. }
英文:

I have a relatively big web application written in Go that uses Gorilla's mux for routing. I recently realised that my web application is quite slow and I would like to profile the web application.

After reading about it, it seems that net/http/pprof is what I need. But I can't make it run with mux; even in the case of the most trivial web application.

Does anyone knows how to make that work?

Here is an example of a trivial code that does not work (i.e. nothing is served at /debug).

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;github.com/gorilla/mux&quot;
  5. &quot;math&quot;
  6. &quot;net/http&quot;
  7. )
  8. import _ &quot;net/http/pprof&quot;
  9. func SayHello(w http.ResponseWriter, r *http.Request) {
  10. for i := 0; i &lt; 1000000; i++ {
  11. math.Pow(36, 89)
  12. }
  13. fmt.Fprint(w, &quot;Hello!&quot;)
  14. }
  15. func main() {
  16. r := mux.NewRouter()
  17. r.HandleFunc(&quot;/hello&quot;, SayHello)
  18. http.ListenAndServe(&quot;:6060&quot;, r)
  19. }

答案1

得分: 36

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

  1. package main
  2. import (
  3. "net/http"
  4. _ "net/http/pprof"
  5. "github.com/gorilla/mux"
  6. )
  7. func main() {
  8. router := mux.NewRouter()
  9. router.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux)
  10. if err := http.ListenAndServe(":6060", router); err != nil {
  11. panic(err)
  12. }
  13. }

我发现这种方法比依赖于隐藏初始化方法的实现更稳定,而且可以确保你没有漏掉任何东西。

英文:

My preferred method for this is to just let net/http/pprof register itself to http.DefaultServeMux, and then pass all requests starting with /debug/pprof/ along:

  1. package main
  2. import (
  3. &quot;net/http&quot;
  4. _ &quot;net/http/pprof&quot;
  5. &quot;github.com/gorilla/mux&quot;
  6. )
  7. func main() {
  8. router := mux.NewRouter()
  9. router.PathPrefix(&quot;/debug/pprof/&quot;).Handler(http.DefaultServeMux)
  10. if err := http.ListenAndServe(&quot;:6060&quot;, router); err != nil {
  11. panic(err)
  12. }
  13. }

I find that this approach is a lot more stable than one that depends on the implementation of a hidden initialization method, and also guarantees that you didn't miss anything.

答案2

得分: 34

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

在你的解决方案中,我无法使用来自Web索引(http://[my-server]/debug/pprof)的链接,直到我添加了一些代码,像这样:

  1. ...
  2. func AttachProfiler(router *mux.Router) {
  3. router.HandleFunc("/debug/pprof/", pprof.Index)
  4. router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
  5. router.HandleFunc("/debug/pprof/profile", pprof.Profile)
  6. router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
  7. // 手动添加对由索引页面链接的路径的支持,路径为 /debug/pprof/
  8. router.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
  9. router.Handle("/debug/pprof/heap", pprof.Handler("heap"))
  10. router.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
  11. router.Handle("/debug/pprof/block", pprof.Handler("block"))
  12. }
  13. ...

如果有其他人遇到同样的问题,希望这能帮到他们!

英文:

user983716 - Thanks for your question and solution!

I was not able to use the links from the web index (http://[my-server]/debug/pprof), until I added a few lines to your solution, like so:

  1. ...
  2. func AttachProfiler(router *mux.Router) {
  3. router.HandleFunc(&quot;/debug/pprof/&quot;, pprof.Index)
  4. router.HandleFunc(&quot;/debug/pprof/cmdline&quot;, pprof.Cmdline)
  5. router.HandleFunc(&quot;/debug/pprof/profile&quot;, pprof.Profile)
  6. router.HandleFunc(&quot;/debug/pprof/symbol&quot;, pprof.Symbol)
  7. // Manually add support for paths linked to by index page at /debug/pprof/
  8. router.Handle(&quot;/debug/pprof/goroutine&quot;, pprof.Handler(&quot;goroutine&quot;))
  9. router.Handle(&quot;/debug/pprof/heap&quot;, pprof.Handler(&quot;heap&quot;))
  10. router.Handle(&quot;/debug/pprof/threadcreate&quot;, pprof.Handler(&quot;threadcreate&quot;))
  11. router.Handle(&quot;/debug/pprof/block&quot;, pprof.Handler(&quot;block&quot;))
  12. }
  13. ...

If anyone has the same problem, I hope this helps!

答案3

得分: 14

抱歉,我只能提供中文翻译。以下是您提供的代码的翻译:

抱歉,对于那个问题。答案在pprof的init()函数中。只需要将4个函数从pprof添加到mux路由器中。以下是修复后的代码。

  1. package main
  2. import (
  3. "fmt"
  4. "github.com/gorilla/mux"
  5. "math"
  6. "net/http"
  7. )
  8. import "net/http/pprof"
  9. func AttachProfiler(router *mux.Router) {
  10. router.HandleFunc("/debug/pprof/", pprof.Index)
  11. router.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
  12. router.HandleFunc("/debug/pprof/profile", pprof.Profile)
  13. router.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
  14. }
  15. func SayHello(w http.ResponseWriter, r *http.Request) {
  16. for i := 0; i < 1000000; i++ {
  17. math.Pow(36, 89)
  18. }
  19. fmt.Fprint(w, "Hello!")
  20. }
  21. func main() {
  22. r := mux.NewRouter()
  23. AttachProfiler(r)
  24. r.HandleFunc("/hello", SayHello)
  25. http.ListenAndServe(":6060", r)
  26. }

希望对您有所帮助!

英文:

Sorry for that question. The answer is in the init() function of pprof. One just need to add 4 functions from pprof to the mux router. Here is the fixed code from above.

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;github.com/gorilla/mux&quot;
  5. &quot;math&quot;
  6. &quot;net/http&quot;
  7. )
  8. import &quot;net/http/pprof&quot;
  9. func AttachProfiler(router *mux.Router) {
  10. router.HandleFunc(&quot;/debug/pprof/&quot;, pprof.Index)
  11. router.HandleFunc(&quot;/debug/pprof/cmdline&quot;, pprof.Cmdline)
  12. router.HandleFunc(&quot;/debug/pprof/profile&quot;, pprof.Profile)
  13. router.HandleFunc(&quot;/debug/pprof/symbol&quot;, pprof.Symbol)
  14. }
  15. func SayHello(w http.ResponseWriter, r *http.Request) {
  16. for i := 0; i &lt; 1000000; i++ {
  17. math.Pow(36, 89)
  18. }
  19. fmt.Fprint(w, &quot;Hello!&quot;)
  20. }
  21. func main() {
  22. r := mux.NewRouter()
  23. AttachProfiler(r)
  24. r.HandleFunc(&quot;/hello&quot;, SayHello)
  25. http.ListenAndServe(&quot;:6060&quot;, r)
  26. }

答案4

得分: 6

我做了其他的事情,我在不同的端口上添加了另一个本地http服务器,它可以直接使用。

  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "net/http"
  6. _ "net/http/pprof"
  7. )
  8. func main() {
  9. go func() {
  10. log.Println(http.ListenAndServe(":6060", nil))
  11. }()
  12. log.Fatalln(http.ListenAndServe(":8080", route.Handlers()))
  13. }

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

英文:

I did something else, I added another native http server on a different port and it just works out of the box

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;log&quot;
  5. &quot;net/http&quot;
  6. _ &quot;net/http/pprof&quot;
  7. )
  8. func main() {
  9. go func() {
  10. log.Println(http.ListenAndServe(&quot;:6060&quot;, nil))
  11. }()
  12. log.Fatalln(http.ListenAndServe(&quot;:8080&quot;, route.Handlers()))
  13. }

Now the pprof endpoint is at :
http://localhost:6060/debug/pprof/ and the applcation is running on port :8080

答案5

得分: 5

之前的示例在我的环境中并没有真正起作用。

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

  1. ...之前的代码
  2. func main() {
  3. r := mux.NewRouter()
  4. r.HandleFunc("/hello", SayHello)
  5. go func() {
  6. log.Fatal(http.ListenAndServe(":6061", http.DefaultServeMux))
  7. }()
  8. http.ListenAndServe(":6060", r)
  9. }

然后访问 http://localhost:6061/debug/pprof/。

英文:

Previous examples not really work on my side.

To use pprof in an existing golang project with gorrila/mux, try to add :

  1. ...previous code
  2. func main() {
  3. r := mux.NewRouter()
  4. r.HandleFunc(&quot;/hello&quot;, SayHello)
  5. go func() {
  6. log.Fatal(http.ListenAndServe(&quot;:6061&quot;, http.DefaultServeMux))
  7. }()
  8. http.ListenAndServe(&quot;:6060&quot;, r)
  9. }

then go to http://localhost:6061/debug/pprof/

答案6

得分: 2

只是这样:

  1. r := mux.NewRouter()
  2. r.PathPrefix("/debug").Handler(http.DefaultServeMux)
英文:

Just so:

  1. r := mux.NewRouter()
  2. r.PathPrefix(&quot;/debug&quot;).Handler(http.DefaultServeMux)

答案7

得分: 0

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

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

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

英文:

Im using https://github.com/julienschmidt/httprouter but i just got this answer from google search.
That's what i did

  1. router := httprouter.New()
  2. router.Handler(&quot;GET&quot;, &quot;/debug/pprof/profile&quot;, http.DefaultServeMux)
  3. router.Handler(&quot;GET&quot;, &quot;/debug/pprof/heap&quot;, http.DefaultServeMux)

I only need this two routes.
This answer is combine of @damien and @user983716 answers.

答案8

得分: 0

以下代码应该可以工作:

  1. import (
  2. "net/http"
  3. _ "net/http/pprof"
  4. )
  5. myrouter.PathPrefix("/debug/pprof/").Handler(http.DefaultServeMux)

这段代码导入了"net/http"和"net/http/pprof"包,并使用myrouter.PathPrefix将"/debug/pprof/"路径的请求交给了http.DefaultServeMux处理。

英文:

The following should work:

  1. import (
  2. &quot;net/http&quot;
  3. _ &quot;net/http/pprof&quot;
  4. )
  5. myrouter.PathPrefix(&quot;/debug/pprof/&quot;).Handler(http.DefaultServeMux)

huangapple
  • 本文由 发表于 2013年10月25日 21:21:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/19591065.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定