我编写了以下GO程序用于目的测试。该http服务器接收get请求,并对另一个rest服务进行http调用。该程序工作正常,但是当我在2vCPU 8 GB框中运行负载测试时。在大约500 TPS之后,它开始提供Http 503。
func retrievedata(w http.ResponseWriter, r *http.Request){
client := &http.Client{
Timeout: time.Second * 5,
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
}
w.Header().Set("Content-Type", "application/json")
urlstring, _ := url.Parse("https://service.dot.com/backendservice/")
req, _ := http.NewRequest("GET", endpointurl, nil)
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
switch resp.StatusCode {
case 200:
data, _ := ioutil.ReadAll(resp.Body)
w.Write(data)
case 404:
w.WriteHeader(http.StatusNotFound)
data, _ := ioutil.ReadAll(resp.Body)
w.Write(data)
case 500:
w.WriteHeader(http.StatusInternalServerError)
data, _ := ioutil.ReadAll(resp.Body)
w.Write(data)
default:
w.WriteHeader(http.StatusNoContent)
}
}
func main() {
fmt.Println("this is a main function")
http.HandleFunc("/getdata", retrievedata)
err := http.ListenAndServe(":8191", nil)
if err != nil {
fmt.Println(err)
}
fmt.Println("Service is Running at port 8191")
}
然后,我添加了go例程以生成处理程序函数
go http.HandleFunc("/getdata", retrievedata)
这次我发现TPS略有增加,但是在大约600 TPS之后仍然出现503错误。请注意,其他rest函数已经针对2000TPS进行了测试,因此我相信这没有问题。
我应该做些什么来获得更多TPS吗?
最佳答案
如果查看transport.go,您将看到:
var DefaultTransport RoundTripper = &Transport{
//...
MaxIdleConns: 100,
IdleConnTimeout: 90 * time.Second,
//...
}
// DefaultMaxIdleConnsPerHost is the default value of Transport's
// MaxIdleConnsPerHost.
const DefaultMaxIdleConnsPerHost = 2
当执行
MaxIdleConns: 100
时,它将连接池的大小设置为100个连接,但是DefaultMaxIdleConnsPerHost
将其设置为每个主机2个。因此,基本上,您的连接池只能容纳2个套接字。因此,如果要执行100个并发请求,则它们完成后,其中两个套接字将在池中保持打开状态,而其他98个套接字将被关闭并以
TIME_WAIT
状态结束。由于这是在负载测试工具的goroutine中发生的,因此您只会在
TIME_WAIT
状态下累积数千个连接。最终,您将用完临时端口,并且无法打开新的客户端连接。defaultRoundTripper := http.DefaultTransport
defaultTransportPtr, ok := defaultRoundTripper.(*http.Transport)
if !ok {
panic(fmt.Sprintf("defaultRoundTripper not an *http.Transport"))
}
defaultTransport := *defaultTransportPtr
defaultTransport.MaxIdleConns = 1000
defaultTransport.MaxIdleConnsPerHost = 1000
client = &http.Client{Transport: &defaultTransport}
最重要的是,您正在做很多工作,而不必在每个请求上都做。您可以这样做:
var client *http.Client
var endpointurl string
var req http.Request
func init() {
defaultRoundTripper := http.DefaultTransport
defaultTransportPtr, ok := defaultRoundTripper.(*http.Transport)
if !ok {
panic(fmt.Sprintf("defaultRoundTripper not an *http.Transport"))
}
defaultTransport := *defaultTransportPtr
defaultTransport.MaxIdleConns = 1000
defaultTransport.MaxIdleConnsPerHost = 1000
defaultTransport.TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
client = &http.Client{Transport: }
client = &http.Client{
Timeout: time.Second * 5,
Transport: &defaultTransport
}
endpointurl, _ = url.Parse("https://service.dot.com/backendservice/")
req, _ := http.NewRequest("GET", endpointurl, nil)
req.Header.Set("Accept", "application/json")
req.Header.Set("Content-Type", "application/json")
}
func retrievedata(w http.ResponseWriter, r *http.Request){
w.Header().Set("Content-Type", "application/json")
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
}
defer resp.Body.Close()
switch resp.StatusCode {
case 200:
data, _ := ioutil.ReadAll(resp.Body)
w.Write(data)
case 404:
w.WriteHeader(http.StatusNotFound)
data, _ := ioutil.ReadAll(resp.Body)
w.Write(data)
case 500:
w.WriteHeader(http.StatusInternalServerError)
data, _ := ioutil.ReadAll(resp.Body)
w.Write(data)
default:
w.WriteHeader(http.StatusNoContent)
}
}
func main() {
fmt.Println("this is a main function")
http.HandleFunc("/getdata", retrievedata)
err := http.ListenAndServe(":8191", nil)
if err != nil {
fmt.Println(err)
}
fmt.Println("Service is Running at port 8191")
}
关于go - Golang http服务器503错误并加载,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/46740386/