go-net/http/client 連線池

語言: CN / TW / HK

攜手創作,共同成長!這是我參與「掘金日新計劃 · 8 月更文挑戰」的第7天,點選檢視活動詳情

前言

最近在搞go的專案,發現專案沒有使用到http client連線池,讓筆者對連線池的必要性、連線池的配置、連線的資損產生了一些思考,除此之外還會給出go http client連線池的示例。

為啥需要連線池

這個和執行緒池優點類似,主要是建立、銷燬會消耗資源和時間,連線還沒到應用層所以是tcp的建立和銷燬。

tcp建立需要經過三次握手,銷燬需要經過四次揮手。消耗的資源主要包括CPU、記憶體(包括各種資料結構及分配的緩衝區),此外還包括fd、埠號等。

因為DMA的存在,所以對cpu的消耗會比較少,但是具體指令需要CPU告訴DMA控制器,比如傳輸什麼資料、從哪裡傳輸到哪裡。此外CPU還會參與TCP頭部的解析。

記憶體可以使用sysctl -A|grep tcp_.mem檢視下: net.ipv4.tcp_rmem = 8192 87380 16777216 net.ipv4.tcp_wmem = 8192 65536 16777216

當然需要避免建立和銷燬是針對同一個host的,所以連線池是每個host的連線池。

所以使用連線池能避免和同一個host頻繁建立和銷燬連線。同時也能限制最大連線數,但是服務一般不去限制,因為會導致進來的請求因為沒有連線響應時間變長,需要做的是最外層的限流和擴容,做的話可以控制下游/第三方服務的壓力,但是下游或者第三方自己應該需要做限流,不需要把控制耦合在上游。

什麼時候需要使用httpclient連線池

如果每次請求的host都不一樣就沒必要用,但是絕大部分服務對外發起的請求都是已知的,不存在隨機或者每次都不一樣。如果是這樣不用管是否請求量,加上肯定比不加好。

不過需要知道的是連線是雙向的,發起方維護了連線,接收方也會維護,接收方會因為發起方的維護而佔用資源,但是筆者認為接收方如果是第三方的時候肯定會考慮到這點,如果是自己的下游服務也需要做好限流和擴容,如果下游服務接收量有限,發起方服務需要做好限流而不是連線池的問題。

建立連線池

``` var ( httpClient *http.Client )

func init() { tr := &http.Transport{ Proxy: http.ProxyFromEnvironment, //InsecureSkipVerify用來控制客戶端是否證書和伺服器主機名。如果設定為true, 則不會校驗證書以及證書中的主機名和伺服器主機名是否一致。 TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, DialContext: (&net.Dialer{ Timeout: 10 * time.Second, //撥號等待連線完成的最大時間 KeepAlive: 30 * time.Second, //保持網路連線活躍keep-alive探測間隔時間。 }).DialContext, MaxIdleConns: 200, IdleConnTimeout: 300 * time.Second, MaxIdleConnsPerHost: 200, } httpClient = &http.Client{ Transport: tr, Timeout: 30 * time.Second, //設定超時,包含connection時間、任意重定向時間、讀取response body時間 } } ```

resp, err := httpClient.Do(req) - Dialer.Timeout:就是等待Connection的時間,這個網路正常情況下毫秒級別的,為了考慮異常情況設定大點,筆者這裡設定了10s。 - Dialer.KeepAlive:當不傳輸的時候保持心跳的間隔。 - Transport.MaxIdleConns:允許的最大空閒連線,可以根據併發平均值去設定,不是越多越好。 - Transport.IdleConnTimeout:空閒連線超時時間,超過了之後回收,最好根據生產流量去設定,不會讓空閒的長期佔用資源,又不至於剛銷燬流量就來了。 - Transport.MaxIdleConnsPerHost:如果只有一個下游服務呼叫就和MaxIdleConns設定成一樣。 - Client.Timeout:包含connection時間、任意重定向時間、讀取response body時間,肯定要大於Dialer.Timeout。

注意:最好依據壓測和生成真實流量配置。

參考

TCP/HTTP連線/Socket/埠

實驗說明 Golang HTTP 連線池引數

一次 HttpClient 連線池設定不當,引發服務雪崩

httpclient連線池使用及簡單分析 About Pool Sizing