go lang http server 503加载错误

时间:2017-10-14 02:54:55

标签: go

我为了目的测试编写了以下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错误。请注意,其他休息功能已经过2000TPS的测试,所以我确信没有问题。 我应该做些不同的事情来获得更多的TPS吗?

1 个答案:

答案 0 :(得分:0)

如果你看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个并发请求,一旦完成,其中2个套接字将在池中保持打开状态,而其他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")
}