文章目錄
- golang 壓力測試
- 前言
-
- 1.普通應用程式 單元+壓力測試
-
- (1). 普通單元測試
- (2). 請求http單元測試
- (3). 請求http壓力測試
- 2.web接口壓力測試
-
- 通過壓測函數直接調用内部handler函數
golang 壓力測試
前言
壓力測試之前,先看下單元測試,主要怕自己忘記,僅供參考
1.普通應用程式 單元+壓力測試
(1). 普通單元測試
go test是golang的單元測試指令
package main
import (
"testing"
)
func Testfunc (t *testing.T) {
邏輯
}
go test -v test.go 代表運作test.go中所有的以Testf命名開始的函數
go test -v -run=“func” test.go 代表運作test.go中所有的Testffunc的函數
-run=“正則表達”
-v 代表檢視詳情
go test是先編譯然後運作,是以支援go build相關的參數
(2). 請求http單元測試
package main
import (
"testing"
"fmt"
"io/ioutil"
"net/http"
"flag"
"net/url"
"io"
"bytes"
"encoding/json"
"github.com/parnurzeal/gorequest"//gorequest需要go get
)
var (
//定義指令行參數,可以go test -arg=
host *string
ip *string
reqUrl string
sign *string
)
func init() {
//解析指令行參數
host = flag.String("host", "127.0.0.1", "請求域名")
ip = flag.String("ip", "127.0.0.1", "請求ip")
fromIp = flag.String("from_ip", "10.78.48.10", "請求來源ip")
sign = flag.String("sign", "c8abc2d3efa0081478beb66e0542eb62", "請求sign")
flag.Parse()
}
func TestReq (t *testing.T) {
send(t, "mock/req.json")
}
//mockFile 代表測試樣本資料
func send(t *testing.T, mockFile string) {
if mockFile == "" {
mockFile = "mock/req.json"
}
defer func() {
if err := recover(); err != nil {
fmt.Println("err =", err)
}
}()
myRequest := url.Values{
}
myRequest.Set("sign", *sign)
myRequest.Set("t", "1554198282793")
myRequest.Set("syn" , "169dd6fc154")
myRequest.Set("n" , "1")
reqUrl = "http://" + *ip + "/req/" + "?" + myRequest.Encode()
reqBody, err := ioutil.ReadFile(mockFile)
if err != nil {
error(err.Error()})
return
}
Request := gorequest.New()
Request.Header = map[string]string{
"X-Forwarded-For": *fromIp,
"Host": *host,
"Content-type" : "application/gzip",
}
resp, data, errs := Request.Post(reqUrl).Type("text").Send(string(reqBody)).EndBytes()
errStr := make([]string, 0)
for _, err := range errs {
if err != nil {
errStr = append(errStr, err.Error())
return
}
}
if resp.StatusCode != http.StatusOK {
error([]string{"return status code error", resp.StatusCode})
return
}
}
1:需要go get github.com/parnurzeal/gorequest
2:單元測試go test -v test.go -args -ip=test.com -host=test.com -sign=ccbb608d5c618ff7d55bedc19de4138f
-args後面跟參數清單
(3). 請求http壓力測試
package main
import (
"testing"
"fmt"
"io/ioutil"
"net/http"
"flag"
"net/url"
"io"
"bytes"
"encoding/json"
"github.com/parnurzeal/gorequest"//gorequest需要go get
)
var (
//定義指令行參數,可以go test -arg=
host *string
ip *string
reqUrl string
sign *string
)
func init() {
//解析指令行參數
host = flag.String("host", "127.0.0.1", "請求域名")
ip = flag.String("ip", "127.0.0.1", "請求ip")
fromIp = flag.String("from_ip", "10.78.48.10", "請求來源ip")
sign = flag.String("sign", "c8abc2d3efa0081478beb66e0542eb62", "請求sign")
flag.Parse()
}
//壓力測試程式
func BenchmarkSend (b *testing.B) {
t := new(testing.T)
b.ReportAllocs()
for i := 0; i < b.N; i++ {
send(t, "")
}
}
//mockFile 代表測試樣本資料
func send(t *testing.T, mockFile string) {
if mockFile == "" {
mockFile = "mock/req.json"
}
defer func() {
if err := recover(); err != nil {
fmt.Println("err =", err)
}
}()
myRequest := url.Values{
}
myRequest.Set("sign", *sign)
myRequest.Set("t", "1554198282793")
myRequest.Set("syn" , "169dd6fc154")
myRequest.Set("n" , "1")
reqUrl = "http://" + *ip + "/req/" + "?" + myRequest.Encode()
reqBody, err := ioutil.ReadFile(mockFile)
if err != nil {
error(err.Error()})
return
}
Request := gorequest.New()
Request.Header = map[string]string{
"X-Forwarded-For": *fromIp,
"Host": *host,
"Content-type" : "application/gzip",
}
resp, data, errs := Request.Post(reqUrl).Type("text").Send(string(reqBody)).EndBytes()
errStr := make([]string, 0)
for _, err := range errs {
if err != nil {
errStr = append(errStr, err.Error())
return
}
}
if resp.StatusCode != http.StatusOK {
error([]string{"return status code error", resp.StatusCode})
return
}
}
壓力測試:
go test -v -run=“none” -bench=“Send*” -benchtime=10s test.go
如果是帶 cpu和記憶體分析的
go test -v -run=“none” -bench=“Send*” -benchtime=10s -cpuprofile cpu.out -memprofile mem.out test.go
簡單的看cpu效果
輸出 上面cpu和記憶體資料 到圖檔
go tool pprof -png cpu.out > cpu.png
也可以直接進入指令行,help查詢相關指令:
go tool pprof cput.out
不過這種http請求壓測看記憶體和trace資料沒有什麼意義
下面介紹不同過http協定,不運作網絡http請求,直接壓測函數内部調用http handler函數,我使用的架構是echo
2.web接口壓力測試
通過壓測函數直接調用内部handler函數
我使用的架構是echo,其他架構應該也差不多,下面代碼僅供參考
package main
import (
"testing"
"fmt"
"io/ioutil"
"net/http"
"flag"
"net/url"
"io"
"bytes"
"encoding/json"
"github.com/parnurzeal/gorequest"//gorequest需要go get
)
var (
//定義指令行參數,可以go test -arg=
host *string
ip *string
reqUrl string
sign *string
)
func init() {
//解析指令行參數
host = flag.String("host", "127.0.0.1", "請求域名")
ip = flag.String("ip", "127.0.0.1", "請求ip")
fromIp = flag.String("from_ip", "10.78.48.10", "請求來源ip")
sign = flag.String("sign", "c8abc2d3efa0081478beb66e0542eb62", "請求sign")
flag.Parse()
}
//壓力測試程式
func BenchmarkSend (b *testing.B) {
//建構請求對象
testData, _ := ioutil.ReadFile("mock/req.json")
req, _ := http.NewRequest("POST", "/req_url", io.Reader(bytes.NewReader(testData)))
req.Header.Set("X-Forwarded-For" , "10.78.48.10")
//new一個response對象
res := new(http.ResponseWriter)
//new 一個context的函數
cont := echo.New().NewContext(req, *res)
b.ReportAllocs()
for i := 0; i < b.N; i++ {
req.Body = ioutil.NopCloser(io.Reader(bytes.NewReader(testData)))
//handles包代表http handler的包
//Handlers.Send代表handles包内部的真正邏輯函數
handlers.Send.Post(cont)
}
}
因為是直接調用的内部handler函數,是以CPU消耗和記憶體都比較真實
如果是帶 cpu和記憶體分析的
go test -v -run=“none” -bench=“Send*” -benchtime=10s -cpuprofile cpu.out -memprofile mem.out test.go
如果要分析攜程調用和網絡阻塞:
go test -v -run=“none” -bench=“Send*” -benchtime=10s -trace=trace.out test.go
go tool trace -http=“host:port” trace.out
通路http:host:port即可看到