1. 程式人生 > >Go語言HTTP測試及程式效能調優

Go語言HTTP測試及程式效能調優

         這篇要講的東西,主要是HTTP,WebSocket的測試及如何調優Go程式的一些方法.
分下面幾個內容:
一.httptest測試包
二.效能測試
三.怎麼利用引數分析和調優程式

四.在執行中實時監控調優

一.httptest測試包
對於HTTP和WebSocket測試,Go標準庫有一個HTTP測試框架.在"http/httptest"包下. 
go1.5.1\go\src\net\http\httptest 


怎麼用可以在原始碼目錄看例子,也可以上官網看看這個例子:
  https://golang.org/src/net/http/request_test.go
裡面各種用法還是很全的.

如果想親自動手試試. https://golang.org/doc/articles/wiki/ 有個很完整的Go Web的例子。
可以搭建起來,再跑一下測試.

比如Post,大致測試程式是這樣的:

func TestPost(t *testing.T) {
	req, err := NewRequest("POST", "http://localhost:8080/edit/nn", strings.NewReader("body=xcl"))
	if err != nil {
		t.Errorf("%v", err)
	}
	defer req.Body.Close()
	req.Header.Set("Content-Type", "application/x-www-form-urlencoded; param=value")

	if q := req.FormValue("body"); q != "xcl" {
		t.Errorf(`req.FormValue("body") = %q, want "xcl"`, q)
	} 
}
二.效能測試

   除了傳統的AB,有一個Go寫的好工具叫boom
   例子:
   boom -n 1000 -c 100 https://google.com
   命令說明:
Usage: boom [options...] <url>

Options:
  -n  Number of requests to run.
  -c  Number of requests to run concurrently. Total number of requests cannot
      be smaller than the concurency level.
  -q  Rate limit, in seconds (QPS).
  -o  Output type. If none provided, a summary is printed.
      "csv" is the only supported alternative. Dumps the response
      metrics in comma-seperated values format.

  -m  HTTP method, one of GET, POST, PUT, DELETE, HEAD, OPTIONS.
  -h  Custom HTTP headers, name1:value1;name2:value2.
  -t  Timeout in ms.
  -A  HTTP Accept header.
  -d  HTTP request body.
  -T  Content-type, defaults to "text/html".
  -a  Basic authentication, username:password.
  -x  HTTP Proxy address as host:port.

  -readall              Consumes the entire request body.
  -allow-insecure       Allow bad/expired TLS/SSL certificates.
  -disable-compression  Disable compression.
  -disable-keepalive    Disable keep-alive, prevents re-use of TCP
                        connections between different HTTP requests.
  -cpus                 Number of used cpu cores.
                        (default for current machine is 1 cores)
  但這個只對HTTP介面之類好使,但像我那種基於WebSocket,使用自定義協議的情況。
還是需要自己定製。
   我目前的做法,客戶端測試直接參考boom的原始碼架構,改成支援WebSocket協議。
並加上指定的自定義協議做業務邏輯模擬,用起來還不錯。不過有個地方要注意,如果一下併發
連線太大,WebSocket的TCP連線建立可能會超時,在定製時可以擴大下等待時長.
程式碼如下:
  //.......
	 client, err := net.DialTimeout("tcp", serverIP, waiteDial*time.Second)
	if err != nil {
		log.Printf("[testConnect] 使用者(%s) net.DialTimeout error:%s", userName, err)
		return
	}
	defer client.Close()

	config, _ := websocket.NewConfig(serverAddr, origin)
	ws, err := websocket.NewClient(config, client)
	if err != nil {
		log.Printf("[testConnect] 使用者(%s)連線伺服器失敗! err:%s", userName, err)
		return
	}
   //.......
三.怎麼利用引數分析和調優程式
/*
調優程式例子

go build main.go
main.exe -cpuprofile=cpu.pprof
go tool pprof main.exe  cpu.pprof

Author:xcl
Date: 2015-11-22
*/

package main

import (
  "flag"
  "fmt"
  "os"
  "runtime/pprof"
)

var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")

func main() {
  flag.Parse()
  if *cpuprofile != "" {
    f, err := os.Create(*cpuprofile)
    if err != nil {
      fmt.Println("Error: ", err)
    }
    pprof.StartCPUProfile(f)
    defer pprof.StopCPUProfile()
  }

  t1()

}

func t1() {
  for i := 0; i < 10000; i++ {
    fmt.Sprintf("%d", i)
  }
}

/*


////////////////////////////////////////////////////

E:\GOtest\testing\testpprof3>go build main.go

E:\GOtest\testing\testpprof3>main.exe -cpuprofile=cpu.pprof

E:\GOtest\testing\testpprof3>dir
 驅動器 E 中的卷是 doc
 卷的序列號是 0E3D-2A1F

 E:\GOtest\testing\testpprof3 的目錄

2015/11/22  18:39    <DIR>          .
2015/11/22  18:39    <DIR>          ..
2015/11/22  18:39               168 cpu.pprof
2015/11/22  18:38         2,826,752 main.exe
2015/11/22  18:38             1,604 main.go
               3 個檔案      2,828,524 位元組
               2 個目錄 15,171,936,256 可用位元組

E:\GOtest\testing\testpprof3>go tool pprof main.exe  cpu.pprof
Entering interactive mode (type "help" for commands)
(pprof) top10
10ms of 10ms total (  100%)
Showing top 10 nodes out of 11 (cum >= 10ms)
      flat  flat%   sum%        cum   cum%
      10ms   100%   100%       10ms   100%  runtime.memmove
         0     0%   100%       10ms   100%  fmt.(*fmt).integer
         0     0%   100%       10ms   100%  fmt.(*fmt).pad
         0     0%   100%       10ms   100%  fmt.(*pp).doPrintf
         0     0%   100%       10ms   100%  fmt.(*pp).fmtInt64
         0     0%   100%       10ms   100%  fmt.(*pp).printArg
         0     0%   100%       10ms   100%  fmt.Sprintf
         0     0%   100%       10ms   100%  main.main
         0     0%   100%       10ms   100%  main.t1
         0     0%   100%       10ms   100%  runtime.goexit
(pprof)

*/
四.在執行中實時監控調優
  其實這個,可以參考原始碼下的 net/http/pprof/pprof.go 
/*
調優程式例子

go build main.go

在瀏覽器邊上檢視
http://127.0.0.1:7081/debug/pprof/
http://127.0.0.1:7081/debug/pprof/profile

Author:xcl
Date: 2015-11-22
*/

package main

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

func main() {
  go func() {
    if err := StartAdminHttp("127.0.0.1:7081"); err != nil {
      os.Exit(-1)
    }
  }()
  t1()
}

func StartAdminHttp(webaddr string) error {
  adminServeMux := http.NewServeMux()
  adminServeMux.HandleFunc("/debug/pprof/", pprof.Index)
  adminServeMux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
  adminServeMux.HandleFunc("/debug/pprof/profile", pprof.Profile)
  adminServeMux.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
  err := http.ListenAndServe(webaddr, adminServeMux)
  if err != nil {
    x := fmt.Sprintf("http.ListenAdServe(\"%s\") failed (%s)", webaddr, err.Error())
    fmt.Println(x)
    return err
  }
  return nil
}

func t1() {
  for i := 0; i < 10000; i++ {
    fmt.Sprintf("%d", i)
    time.Sleep(1 * time.Second)
  }
}
另外一種做法:
  在程式執行中,在命令列視窗,執行"go tool pprof url... "會也成相應的文件.
以profile為例,會等待30s,然後在  \pprof\ 生成相關文件。 然後可使用pprof相關命令來調優。
C:\Users\XCL>go tool pprof http://127.0.0.1:7081/debug/pprof/profile
Fetching profile from http://127.0.0.1:7081/debug/pprof/profile
Please wait... (30s)
Saved profile in \pprof\pprof.127.0.0.1:7081.samples.cpu.001.pb.gz
Entering interactive mode (type "help" for commands)
(pprof)
(pprof)
(pprof) top10
10ms of 10ms total (  100%)
      flat  flat%   sum%        cum   cum%
      10ms   100%   100%       10ms   100%  runtime.runqput
         0     0%   100%       10ms   100%  runtime.goready.func1
         0     0%   100%       10ms   100%  runtime.ready
         0     0%   100%       10ms   100%  runtime.startTheWorldWithSema
         0     0%   100%       10ms   100%  runtime.systemstack
(pprof)

參考文件: 
  https://golang.org/cmd/go/#hdr-Description_of_testing_flags
  http://saml.rilspace.org/profiling-and-creating-call-graphs-for-go-programs-with-go-tool-pprof
  http://www.cnblogs.com/yjf512/archive/2012/12/27/2835331.html



BLOG: http://blog.csdn.net/xcl168