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

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

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路径下没有任何内容被提供)。

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)
}
英文:

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

package main

import (
	&quot;fmt&quot;
	&quot;github.com/gorilla/mux&quot;
	&quot;math&quot;
	&quot;net/http&quot;
)
import _ &quot;net/http/pprof&quot;

func SayHello(w http.ResponseWriter, r *http.Request) {
	for i := 0; i &lt; 1000000; i++ {
		math.Pow(36, 89)
	}
	fmt.Fprint(w, &quot;Hello!&quot;)
}

func main() {
	r := mux.NewRouter()
	r.HandleFunc(&quot;/hello&quot;, SayHello)
	http.ListenAndServe(&quot;:6060&quot;, r)
}

答案1

得分: 36

我个人偏好的方法是让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)
	}
}

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

英文:

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:

package main

import (
	&quot;net/http&quot;
	_ &quot;net/http/pprof&quot;

	&quot;github.com/gorilla/mux&quot;
)

func main() {
	router := mux.NewRouter()
	router.PathPrefix(&quot;/debug/pprof/&quot;).Handler(http.DefaultServeMux)
	if err := http.ListenAndServe(&quot;:6060&quot;, router); err != nil {
		panic(err)
	}
}

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)的链接,直到我添加了一些代码,像这样:

...

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)

    // 手动添加对由索引页面链接的路径的支持,路径为 /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"))
}

...

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

英文:

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:

...

func AttachProfiler(router *mux.Router) {
    router.HandleFunc(&quot;/debug/pprof/&quot;, pprof.Index)
    router.HandleFunc(&quot;/debug/pprof/cmdline&quot;, pprof.Cmdline)
    router.HandleFunc(&quot;/debug/pprof/profile&quot;, pprof.Profile)
    router.HandleFunc(&quot;/debug/pprof/symbol&quot;, pprof.Symbol)

    // Manually add support for paths linked to by index page at /debug/pprof/
    router.Handle(&quot;/debug/pprof/goroutine&quot;, pprof.Handler(&quot;goroutine&quot;))
    router.Handle(&quot;/debug/pprof/heap&quot;, pprof.Handler(&quot;heap&quot;))
    router.Handle(&quot;/debug/pprof/threadcreate&quot;, pprof.Handler(&quot;threadcreate&quot;))
    router.Handle(&quot;/debug/pprof/block&quot;, pprof.Handler(&quot;block&quot;))
}

...

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

答案3

得分: 14

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

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

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

希望对您有所帮助!

英文:

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.

package main

import (
	&quot;fmt&quot;
	&quot;github.com/gorilla/mux&quot;
	&quot;math&quot;
        
	&quot;net/http&quot;
)
import &quot;net/http/pprof&quot;

func AttachProfiler(router *mux.Router) {
	router.HandleFunc(&quot;/debug/pprof/&quot;, pprof.Index)
	router.HandleFunc(&quot;/debug/pprof/cmdline&quot;, pprof.Cmdline)
	router.HandleFunc(&quot;/debug/pprof/profile&quot;, pprof.Profile)
	router.HandleFunc(&quot;/debug/pprof/symbol&quot;, pprof.Symbol)
}

func SayHello(w http.ResponseWriter, r *http.Request) {
	for i := 0; i &lt; 1000000; i++ {
		math.Pow(36, 89)
	}
	fmt.Fprint(w, &quot;Hello!&quot;)
}

func main() {
	r := mux.NewRouter()
	AttachProfiler(r)
	r.HandleFunc(&quot;/hello&quot;, SayHello)
	http.ListenAndServe(&quot;:6060&quot;, r)
}

答案4

得分: 6

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

英文:

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

package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;net/http&quot;

	_ &quot;net/http/pprof&quot;
)


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

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,请尝试添加以下代码:

...之前的代码

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

英文:

Previous examples not really work on my side.

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

...previous code

func main() {
    r := mux.NewRouter()
    r.HandleFunc(&quot;/hello&quot;, SayHello)

    go func() {
        log.Fatal(http.ListenAndServe(&quot;:6061&quot;, http.DefaultServeMux))
    }()

    http.ListenAndServe(&quot;:6060&quot;, r)
}

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

答案6

得分: 2

只是这样:

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

Just so:

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

答案7

得分: 0

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

英文:

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

router := httprouter.New()
router.Handler(&quot;GET&quot;, &quot;/debug/pprof/profile&quot;, http.DefaultServeMux)
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

以下代码应该可以工作:

import (
    "net/http"
    _ "net/http/pprof"
)

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

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

英文:

The following should work:

import (
 &quot;net/http&quot;
 _ &quot;net/http/pprof&quot;
)

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:

确定