多线程如何影响http保活连接?

How does multithreading affect http keep-alive connection?

var (
    httpClient *http.Client
)

const (
    MaxIdleConnections int = 20
    RequestTimeout     int = 5
)

// init HTTPClient
func init() {
    client := &http.Client{
        Transport: &http.Transport{
            MaxIdleConnsPerHost: MaxIdleConnections,
        },
        Timeout: time.Duration(RequestTimeout) * time.Second,
    }

    return client
}

func makeRequest() {
    var endPoint string = "https://localhost:8080/doSomething"

    req, err := http.NewRequest("GET", ....)
    
    response, err := httpClient.Do(req)
    if err != nil && response == nil {
        log.Fatalf("Error sending request to API endpoint. %+v", err)
    } else {
        // Close the connection to reuse it
        defer response.Body.Close()
        body, err := ioutil.ReadAll(response.Body)
        if err != nil {
            log.Fatalf("Couldn't parse response body. %+v", err)
        }
        
        log.Println("Response Body:", string(body))
    }
}

我在 Go 中有以下代码。 Go 使用 http-keep-alive 连接。因此,根据我的理解,httpClient.Do(req) 不会创建新连接,因为 golang 使用默认的持久连接。

  1. 根据我的理解,HTTP持久连接一次只发出一个请求,即第二次请求只能在第一次响应后发出。但是,如果多个线程调用 makeRequest() 会发生什么? httpClient.Do(req) 会在前一个请求得到响应之前发送另一个请求吗?

  2. 我假设服务器超时客户端建立的任何保持连接。如果服务器超时,那么下次调用 httpClient.Do(req) 时,它会建立新的连接吗?

一个 http.Client 有一个 Transport ,它将发出请求的许多 low-level 细节委托给它。通过为客户提供自定义传输,您几乎可以更改任何内容。该答案的其余部分将主要假设您正在使用 http.DefaultClient 或至少使用 http.DefaultTransport.

的客户端

发出新请求时,如果到相应服务器的空闲连接可用,传输将使用它。

如果没有可用的空闲连接(因为从来没有,或者因为其他 goroutines 正在使用它们,或者因为服务器关闭了连接,或者有一些其他错误)那么传输将考虑创建一个新的连接数,受 MaxConnsPerHost 限制(默认:无限制)。如果超过 MaxConnsPerHost,则请求将阻塞,直到现有请求完成并且连接可用。否则,将为该请求建立新连接。

请求完成后,客户端将缓存连接供以后使用(受MaxIdleConnsMaxIdleConnsPerHost限制;DefaultTransport全局限制为100个空闲连接,并且没有限制 per-host).

空闲连接将在 IdleConnTimeout 后关闭,如果它们不用于发出请求; DefaultTransport 的限制是 90 秒。

所有这些意味着默认情况下,Go 将建立足够的连接来满足并行性(达到您可以调整的某些限制),但它也会通过维护池来尽可能多地重用 keep-alive 个连接一段时间内的空闲连接数。

它不会影响 http keep-alive 连接,根据您的代码,您使用的是全局 httpClient,如果像您预期的那样在多线程中调用,这将不会创建新连接,它还读取 response.Body 在它关闭之前。如果提供的 response.Bodyio.Closer,它将在请求后关闭。