-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathstress_testing.go
executable file
·206 lines (185 loc) · 4.23 KB
/
stress_testing.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*
* Description : 接口压力测试, 并输出结果 TODO 测试
* Author : ManGe
* Mail : 2912882908@qq.com
**/
package gathertool
import (
"log"
"net"
"net/http"
"sync"
"sync/atomic"
"time"
)
type stateCodeData struct {
Code int
ReqTime int64
}
// StressUrl 压力测试一个url
type StressUrl struct {
Url string
Method string
Sum int64
Total int
TQueue TodoQueue
// 请求时间累加
sumReqTime int64
// 测试结果
avgReqTime time.Duration
// 接口传入的json
JsonData string
// 接口传入类型
ContentType string
// 是否重试
isRetry bool
stateCodeList []*stateCodeData
stateCodeListMux *sync.Mutex
}
// NewTestUrl 实例化一个新的url压测
func NewTestUrl(url, method string, sum int64, total int) *StressUrl {
return &StressUrl{
Url: url,
Method: method,
Sum: sum,
Total: total,
TQueue: NewQueue(),
sumReqTime: int64(0),
isRetry: false,
stateCodeList: make([]*stateCodeData, 0),
stateCodeListMux: &sync.Mutex{},
}
}
// SetJson 设置json
func (s *StressUrl) SetJson(str string) {
s.JsonData = str
}
func (s *StressUrl) OpenRetry() {
s.isRetry = true
}
// Run 运行压测
func (s *StressUrl) Run(vs ...any) {
//解析可变参
var (
succeedFunc SucceedFunc
n int64
wg sync.WaitGroup
reqTimeout ReqTimeOut
reqTimeoutMs ReqTimeOutMs
header http.Header
)
for _, v := range vs {
switch vv := v.(type) {
// 使用方传入了 header
case SucceedFunc:
succeedFunc = vv
case ReqTimeOut:
reqTimeout = vv
case ReqTimeOutMs:
reqTimeoutMs = vv
case http.Header:
header = vv
case *http.Header:
header = *vv
}
}
//初始化队列
for n = 0; n < s.Sum; n++ {
_ = s.TQueue.Add(&Task{Url: s.Url})
}
log.Println("总执行次数: ", s.TQueue.Size())
var count int64 = 0
for job := 0; job < s.Total; job++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
for {
var (
ctx = &Context{}
)
if s.TQueue.IsEmpty() {
break
}
task := s.TQueue.Poll()
if task == nil {
continue
}
// 定义适用于压力测试的client
t := http.DefaultTransport.(*http.Transport).Clone()
t.MaxIdleConns = s.Total * 2
t.MaxIdleConnsPerHost = s.Total * 2
t.DisableKeepAlives = true
t.DialContext = (&net.Dialer{
Timeout: 3 * time.Second,
KeepAlive: 3 * time.Second,
}).DialContext
t.IdleConnTimeout = 3 * time.Second
t.ExpectContinueTimeout = 1 * time.Second
client := http.Client{
Transport: t,
Timeout: 1 * time.Second,
}
switch s.Method {
case "get", "Get", "GET":
ctx = NewGet(task.Url, client, succeedFunc, reqTimeout, reqTimeoutMs, header)
case "post", "Post", "POST":
ctx = NewPost(task.Url, []byte(s.JsonData), s.ContentType, client, succeedFunc, reqTimeout, reqTimeoutMs, header)
default:
log.Println("暂时不支持的 Method.")
}
if ctx == nil {
continue
}
ctx.JobNumber = i
if !s.isRetry {
ctx.CloseRetry()
}
ctx.Do()
atomic.AddInt64(&s.sumReqTime, int64(ctx.Ms))
atomic.AddInt64(&count, int64(1))
s.stateCodeListMux.Lock()
if ctx.Resp != nil {
s.stateCodeList = append(s.stateCodeList, &stateCodeData{
Code: ctx.Resp.StatusCode,
ReqTime: int64(ctx.Ms),
})
} else {
//请求错误
s.stateCodeList = append(s.stateCodeList, &stateCodeData{
Code: -1,
ReqTime: int64(ctx.Ms),
})
}
s.stateCodeListMux.Unlock()
}
}(job)
}
wg.Wait()
Info("执行次数 : ", count)
var (
maxTime int64 = 0
minTime int64 = 9999999999
)
fb := make(map[int]int)
for _, v := range s.stateCodeList {
if v.ReqTime >= maxTime {
maxTime = v.ReqTime
}
if v.ReqTime <= minTime {
minTime = v.ReqTime
}
if _, ok := fb[v.Code]; ok {
fb[v.Code]++
} else {
fb[v.Code] = 1
}
//s.sumReqTime = s.sumReqTime + v.ReqTime
}
Info("状态码分布: ", fb)
avg := float64(s.sumReqTime) / float64(s.Sum)
avg = avg / (1000 * 1000)
Info("平均用时: ", avg, "ms")
Info("最高用时: ", float64(maxTime)/(1000*1000), "ms")
Info("最低用时: ", float64(minTime)/(1000*1000), "ms")
Info("执行完成!!!")
}