# 12.7.1 分析HTTP服务

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

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

* <http://localhost:8080/debug/pprof/goroutine>
* <http://localhost:8080/debug/pprof/heap>
* <http://localhost:8080/debug/pprof/theadcreate>
* <http://localhost:8080/debug/pprof/block>
* <http://localhost:8080/debug/pprof/mutex>
* <http://localhost:8080/debug/pprof/profile>
* <http://localhost:8080/debug/pprof/trace?seconds=5>

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

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

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

```go
package main

import (
    "fmt"
    "net/http"
    "net/http/pprof"
    "os"
    "time"
)

func myHandler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
    fmt.Printf("Served: %s\n", r.Host)
}

func timeHandler(w http.ResponseWriter, r *http.Request) {
    t := time.Now().Format(time.RFC1123)
    Body := "The current time is:"
    fmt.Fprintf(w, "<h1 align=\"center\">%s</h1>", Body)
    fmt.Fprintf(w, "<h2 align=\"center\">%s</h2>\n", t)
    fmt.Fprintf(w, "Serving: %s\n", r.URL.Path)
    fmt.Printf("Served time for: %s\n", r.Host)    
}
```

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

`wwwProfile.go` 的第二段代码如下：

```go
func main() {
    PORT := ":8001"
    arguments := os.Args
    if len(arguments) == 1 {
        fmt.Println("Using default port number: ", PORT)
    }else{
        PORT = ":" + arguments[1]
        fmt.Println("Using port number: ", PORT)
    }

    r := http.NewServeMux()
    r.HandleFunc("/time", timeHandler)
    r.HandleFunc("/", myHandler)
```

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

`wwwProfile.go` 的第三段代码如下：

```go
    r.HandleFunc("/debug/pprof/", pprof.Index)
    r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
    r.HandleFunc("/debug/pprof/profile", pprof.Profile)
    r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
    r.HandleFunc("/debug/pprof/trace", pprof.Trace)
```

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

余下的 Go 代码如下：

```go
    err := http.ListenAndServe(PORT, r)
    if err != nil {
        fmt.Println(err)
        return
    }
}
```

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

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

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

```
$ go run wwwProfile.go 1234
Using port number: :1234
Served time for: localhost:1234
```

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

![](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/images/chapter12/12.7.1-1.jpg)

如您在[第11章](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/eBook/chapter11/11.0.md)（代码测试，优化和分析）中了解到的，您现在可以使用这个分析数据，并使用 `go tool pprof`分析它。

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

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

![](https://github.com/hantmac/Mastering_Go_ZH_CN/tree/master/images/chapter12/12.7.1-2.jpg)
