我编写了以下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/

10-11 02:40