文章目录
    golang 压力测试
    前言
    1.普通应用程序 单元+压力测试
    (1). 普通单元测试
    (2). 请求http单元测试
    (3). 请求http压力测试
    2.web接口压力测试
    通过压测函数直接调用内部handler函数
    golang 压力测试
    前言
    压力测试之前,先看下单元测试,主要怕自己忘记,仅供参考

    1.普通应用程序 单元+压力测试
    (1). 普通单元测试
    go test是golang的单元测试命令

    1. package main
    2. import (
    3. "testing"
    4. func Testfunc (t *testing.T) {
    5. 逻辑
    6. }

    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单元测试

    1. package main
    2. import (
    3. "testing"
    4. "fmt"
    5. "io/ioutil"
    6. "net/http"
    7. "flag"
    8. "net/url"
    9. "io"
    10. "bytes"
    11. "encoding/json"
    12. "github.com/parnurzeal/gorequest"//gorequest需要go get
    13. )
    14. var (
    15. //定义命令行参数,可以go test -arg=
    16. host *string
    17. ip *string
    18. reqUrl string
    19. sign *string
    20. )
    21. func init() {
    22. //解析命令行参数
    23. host = flag.String("host", "127.0.0.1", "请求域名")
    24. ip = flag.String("ip", "127.0.0.1", "请求ip")
    25. fromIp = flag.String("from_ip", "10.78.48.10", "请求来源ip")
    26. sign = flag.String("sign", "c8abc2d3efa0081478beb66e0542eb62", "请求sign")
    27. flag.Parse()
    28. }
    29. func TestReq (t *testing.T) {
    30. send(t, "mock/req.json")
    31. }
    32. //mockFile 代表测试样本数据
    33. func send(t *testing.T, mockFile string) {
    34. if mockFile == "" {
    35. mockFile = "mock/req.json"
    36. }
    37. defer func() {
    38. if err := recover(); err != nil {
    39. fmt.Println("err =", err)
    40. }
    41. }()
    42. myRequest := url.Values{
    43. }
    44. myRequest.Set("sign", *sign)
    45. myRequest.Set("t", "1554198282793")
    46. myRequest.Set("syn" , "169dd6fc154")
    47. myRequest.Set("n" , "1")
    48. reqUrl = "http://" + *ip + "/req/" + "?" + myRequest.Encode()
    49. reqBody, err := ioutil.ReadFile(mockFile)
    50. if err != nil {
    51. error(err.Error()})
    52. return
    53. }
    54. Request := gorequest.New()
    55. Request.Header = map[string]string{
    56. "X-Forwarded-For": *fromIp,
    57. "Host": *host,
    58. "Content-type" : "application/gzip",
    59. }
    60. resp, data, errs := Request.Post(reqUrl).Type("text").Send(string(reqBody)).EndBytes()
    61. errStr := make([]string, 0)
    62. for _, err := range errs {
    63. if err != nil {
    64. errStr = append(errStr, err.Error())
    65. return
    66. }
    67. }
    68. if resp.StatusCode != http.StatusOK {
    69. error([]string{"return status code error", resp.StatusCode})
    70. return
    71. }
    72. }

    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压力测试

    1. package main
    2. import (
    3. "testing"
    4. "fmt"
    5. "io/ioutil"
    6. "net/http"
    7. "flag"
    8. "net/url"
    9. "io"
    10. "bytes"
    11. "encoding/json"
    12. "github.com/parnurzeal/gorequest"//gorequest需要go get
    13. )
    14. var (
    15. //定义命令行参数,可以go test -arg=
    16. host *string
    17. ip *string
    18. reqUrl string
    19. sign *string
    20. )
    21. func init() {
    22. //解析命令行参数
    23. host = flag.String("host", "127.0.0.1", "请求域名")
    24. ip = flag.String("ip", "127.0.0.1", "请求ip")
    25. fromIp = flag.String("from_ip", "10.78.48.10", "请求来源ip")
    26. sign = flag.String("sign", "c8abc2d3efa0081478beb66e0542eb62", "请求sign")
    27. flag.Parse()
    28. }
    29. //压力测试程序
    30. func BenchmarkSend (b *testing.B) {
    31. t := new(testing.T)
    32. b.ReportAllocs()
    33. for i := 0; i < b.N; i++ {
    34. send(t, "")
    35. }
    36. }
    37. //mockFile 代表测试样本数据
    38. func send(t *testing.T, mockFile string) {
    39. if mockFile == "" {
    40. mockFile = "mock/req.json"
    41. }
    42. defer func() {
    43. if err := recover(); err != nil {
    44. fmt.Println("err =", err)
    45. }
    46. }()
    47. myRequest := url.Values{
    48. }
    49. myRequest.Set("sign", *sign)
    50. myRequest.Set("t", "1554198282793")
    51. myRequest.Set("syn" , "169dd6fc154")
    52. myRequest.Set("n" , "1")
    53. reqUrl = "http://" + *ip + "/req/" + "?" + myRequest.Encode()
    54. reqBody, err := ioutil.ReadFile(mockFile)
    55. if err != nil {
    56. error(err.Error()})
    57. return
    58. }
    59. Request := gorequest.New()
    60. Request.Header = map[string]string{
    61. "X-Forwarded-For": *fromIp,
    62. "Host": *host,
    63. "Content-type" : "application/gzip",
    64. }
    65. resp, data, errs := Request.Post(reqUrl).Type("text").Send(string(reqBody)).EndBytes()
    66. errStr := make([]string, 0)
    67. for _, err := range errs {
    68. if err != nil {
    69. errStr = append(errStr, err.Error())
    70. return
    71. }
    72. }
    73. if resp.StatusCode != http.StatusOK {
    74. error([]string{"return status code error", resp.StatusCode})
    75. return
    76. }
    77. }

    压力测试:
    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,其他框架应该也差不多,下面代码仅供参考

    1. package main
    2. import (
    3. "testing"
    4. "fmt"
    5. "io/ioutil"
    6. "net/http"
    7. "flag"
    8. "net/url"
    9. "io"
    10. "bytes"
    11. "encoding/json"
    12. "github.com/parnurzeal/gorequest"//gorequest需要go get
    13. )
    14. var (
    15. //定义命令行参数,可以go test -arg=
    16. host *string
    17. ip *string
    18. reqUrl string
    19. sign *string
    20. )
    21. func init() {
    22. //解析命令行参数
    23. host = flag.String("host", "127.0.0.1", "请求域名")
    24. ip = flag.String("ip", "127.0.0.1", "请求ip")
    25. fromIp = flag.String("from_ip", "10.78.48.10", "请求来源ip")
    26. sign = flag.String("sign", "c8abc2d3efa0081478beb66e0542eb62", "请求sign")
    27. flag.Parse()
    28. }
    29. //压力测试程序
    30. func BenchmarkSend (b *testing.B) {
    31. //构建请求对象
    32. testData, _ := ioutil.ReadFile("mock/req.json")
    33. req, _ := http.NewRequest("POST", "/req_url", io.Reader(bytes.NewReader(testData)))
    34. req.Header.Set("X-Forwarded-For" , "10.78.48.10")
    35. //new一个response对象
    36. res := new(http.ResponseWriter)
    37. //new 一个context的函数
    38. cont := echo.New().NewContext(req, *res)
    39. b.ReportAllocs()
    40. for i := 0; i < b.N; i++ {
    41. req.Body = ioutil.NopCloser(io.Reader(bytes.NewReader(testData)))
    42. //handles包代表http handler的包
    43. //Handlers.Send代表handles包内部的真正逻辑函数
    44. handlers.Send.Post(cont)
    45. }
    46. }

    因为是直接调用的内部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即可看到
    ————————————————
    版权声明:本文为CSDN博主「wo44xmh」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/wo44xmh/article/details/101099702