《使用 Go 程序进行 HTTP 压测》

《使用 Go 程序进行 HTTP 压测》

用 Go 并发发起 HTTP 请求做简单的压力测试:模拟 N 个用户、每个用户连续请求 M 次,验证验证码服务的性能。

1. 压测主程序

package main import ( "encoding/json" "fmt" "io/ioutil" "log" "net/http" "net/url" "sync" ) type Session struct { Sessionstr string Success string } var PUB = "YOUR_PUBLIC_KEY" func getSession() string { resp, err := http.Get(fmt.Sprintf("http://YOUR_HOST:8515/session_cb?pub=%s", PUB)) if err != nil { log.Println(err) return "" } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { log.Println(err) return "" } strBody := string(body) length := len(strBody) var session Session json.Unmarshal([]byte(strBody[9:length-1]), &session) return session.Sessionstr } func getImage(session string) { resp, err := http.Get(fmt.Sprintf("http://YOUR_SERVER:8515/image?session=%s&pub=%s", session, PUB)) if err != nil { log.Println(err) } defer resp.Body.Close() } func verify(session string) { requestBody := url.Values{ "response": {"12345"}, "challenge": {session}, "privatekey": {"xx"}, "remoteip": {"1.1.1.1"}, } resp, err := http.PostForm("http://YOUR_SERVER:8515/verify", requestBody) if err != nil { log.Println(err) } defer resp.Body.Close() } func main() { // 增大每个主机的最大空闲连接数,防止压测时 TCP 连接耗尽 http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = 4096 const userNumber = 500 // 模拟用户数 const requestNumber = 1000 // 每个用户请求次数 var wg sync.WaitGroup wg.Add(userNumber) for num := 0; num < userNumber; num++ { go func() { defer wg.Done() for cnt := 0; cnt < requestNumber; cnt++ { session := getSession() getImage(session) verify(session) } }() } wg.Wait() }

2. 压测问题

2.1 Cannot assign requested address

由于 Linux 分配的客户端连接端口用尽,无法建立新的 socket。虽然 socket 正常关闭,但端口不是立即释放,而是进入 TIME_WAIT 状态,默认等 60s 后才释放。

现象:ss -a | wc -l 连接数持续飙升,最终没有可用的 socket 连接。

解决:修改 /etc/sysctl.conf

net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.tcp_fin_timeout = 30

立即生效:

sysctl -p

说明:tcp_tw_reuse + tcp_tw_recycle 用于复用 TIME_WAIT 连接,加速端口回收。

阅读 — · 全站 —
🎸 我的歌单 0 首