分析 HTTP 服务

如您在第11章(代码测试,优化和分析)中了解到的,有个名为 net/http/pprof 标准包,当您想要用它自己的 HTTP 服务分析一个 Go 应用时,可以使用它。因此,导入 net/http/pprof 将在 /debug/pprof/ URL 下安装各种处理程序。您很快就会看到更多的情况。现在,您记住 net/http/pprof 包应该用于用 HTTP 服务分析 web 应用就足够了,而 runtime/pprof 标准包应该用于分析其他类型的应用。

注意,如果您的分析器工作在 http://localhost:8080 地址,您将从 如下 web 链接获得支持:

下面被展示的程序将使用 www.go 做为起始点,并添加必要的 Go 代码允许您去分析它。这个新程序命名为 wwwProfile.go,分为四部分展示。

注意,wwwProfile.go 将使用一个 http.NewServeMux 变量用于注册程序支持的路径。这样做的主要原因是,使用 http.NewServeMux需要手动定义 HTTP 端点。如果您决定不使用 http.NewServeMux,那么 HTTP 端点将自动注册,这也意味着您将使用 _ 字符在引入的 net/http/pprof 包前。

wwwProfile.go 第一部分包含的 Go 代码如下:

  1. package main
  2. import (
  3. "fmt"
  4. "net/http"
  5. "net/http/pprof"
  6. "os"
  7. "time"
  8. )
  9. func myHandler(w http.ResponseWriter, r *http.Request) {
  10. fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
  11. fmt.Printf("Served: %s\n", r.Host)
  12. }
  13. func timeHandler(w http.ResponseWriter, r *http.Request) {
  14. t := time.Now().Format(time.RFC1123)
  15. Body := "The current time is:"
  16. fmt.Fprintf(w, "<h1 align=\"center\">%s</h1>", Body)
  17. fmt.Fprintf(w, "<h2 align=\"center\">%s</h2>\n", t)
  18. fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
  19. fmt.Printf("Served time for: %s\n", r.Host)
  20. }

这俩个处理函数的实现与之前的一样。

wwwProfile.go 的第二段代码如下:

  1. func main() {
  2. PORT := ":8001"
  3. arguments := os.Args
  4. if len(arguments) == 1 {
  5. fmt.Println("Using default port number: ", PORT)
  6. }else{
  7. PORT = ":" + arguments[1]
  8. fmt.Println("Using port number: ", PORT)
  9. }
  10. r := http.NewServeMux()
  11. r.HandleFunc("/time", timeHandler)
  12. r.HandleFunc("/", myHandler)

在上面的 Go 代码中,您使用 http.NewServeMux()HandleFunc() 定义您的 web 服务支持的 URL。

wwwProfile.go 的第三段代码如下:

  1. r.HandleFunc("/debug/pprof/", pprof.Index)
  2. r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
  3. r.HandleFunc("/debug/pprof/profile", pprof.Profile)
  4. r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
  5. r.HandleFunc("/debug/pprof/trace", pprof.Trace)

上面的 Go 代码定义与分析相关的 HTTP 端点。没有它们,您将不能分析您的 web 应用。

余下的 Go 代码如下:

  1. err := http.ListenAndServe(PORT, r)
  2. if err != nil {
  3. fmt.Println(err)
  4. return
  5. }
  6. }

这段代码启动 web 服务,并允许它服务来自 HTTP 客户端的连接。您会注意到 http.ListenAndServe() 的第二个参数不再是 nil

如您所见,wwwProfile.go 没有定义 /debug/pprof/goroutine HTTP 端点,这意味着 wwwProfile.go 不使用任何 goroutines !

执行 wwwProfile.go 将产生如下输出:

  1. $ go run wwwProfile.go 1234
  2. Using port number: :1234
  3. Served time for: localhost:1234

使用 Go 分析器获取数据是相当简单的任务,执行下面的命令将带您自动进入 Go 分析器的 shell。

12.7.1 分析HTTP服务 - 图1

如您在第11章(代码测试,优化和分析)中了解到的,您现在可以使用这个分析数据,并使用 go tool pprof分析它。

您可以访问 http://HOSTNAME:PORTNUMBER/debug/pprof,从那可以看到分析结果。当 HOSTNAME 的值是 localhostPORTNUMBER 的值是 1234 时,您应该访问 http://localhost:1234/debug/pprof/

您应该希望测试您的 web 服务应用的性能,您可以使用 ab(1) 工具,它做为 Apache HTTP server benchmarking tool 广为人知,用于创建流量和基准。这也允许 go tool pprof 收集更多的准确数据,如下:

12.7.1 分析HTTP服务 - 图2