使用Go HTTP客戶端打造高性能服務

HTTP(超文本傳輸協議)是一種用於客戶端和服務器之間傳輸數據的通信協議。如果想要訪問服務器資源,HTTP 請求是必不可少的。Go 語言裡,net/http 包附帶瞭默認配置,我們可以適當調整便可以獲得高性能。

大多數語言都有提供各自的 HTTP 客戶端,文章接下來部分我們將動手實踐如何使用 Go 語言發起 HTTP 請求,並討論其中有可能遇到的問題。

在做 Go 項目時,我就意識到 HTTP 客戶端如果配置不正確可能會隨時導致服務器崩潰。

在使用 HTTP Client 時,我觀察到一些問題並總結出相應的解決方案,如下所示:

問題一:默認的 HTTP Client

默認情況下,net/http 包自帶的 HTTP 客戶端不帶超時時間。如果你使用的是默認的客戶端 http.DefaultClient(),這個是不帶超時時間的。

假如你請求外部的 API 掛瞭,發出的請求沒響應導致連接一直出於打開狀態。隨著請求數越來越多,連接數隨之增加,導致耗盡服務器的資源,最後服務器隨之崩潰。

解決辦法:不要使用默認的 HTTP 客戶端,根據實際情況設置超時時間。

var httpClient = &http.Client{
  Timeout: time.Second * 10,
}

對於 API 接口,超時時間建議不需要超過 10s,如果請求在 10s 內沒有返回,則請求會取消並報錯:request canceled (Client.Timeout exceeded …) 。

問題二:默認的 Http Transport

默認情況下,HTTP 客戶端會維護一個連接池。當請求完成之後,連接會保持打開狀態直到空閑時間超時(默認是 90s)自動斷開。如果有請求過來,會優先使用已打開的連接而不是創建新的連接,請求完成之後,連接會返還到連接池中。

使用連接池將使用最少的服務器資源處理更多的 API 請求。

如果沒有自定義 HTTP 客戶端的 transport,將會使用默認配置。

HTTP Transport 的默認配置如下:

var DefaultTransport RoundTripper = &Transport{
    ...
    MaxIdleConns:          100,
    IdleConnTimeout:       90 * time.Second,
    ...
}

 
const DefaultMaxIdleConnsPerHost = 2

MaxIdleConns 表示連接池大小,是可以打開的最大連接數,默認值是 100。

參數 DefaultMaxIdleConnsPerHost 的默認值是 2,表示每個主機(host)的打開連接數。這意味著,連接池中 100 個連接隻有兩個連接分配給該主機。

隨著請求增多,但是隻有兩個請求被處理,其他請求隻能被迫等待並進入 TIME_WAIT 狀態。請求增多,進入 TIME_WAIT 狀態的連接數增多,消耗越來越多的服務器資源,當達到服務器瓶頸時,服務器將會崩潰。

解決辦法:提高 MaxIdleConnsPerHost 數值,不要使用默認的 Transport。

t := http.DefaultTransport.(*http.Transport).Clone()
t.MaxIdleConns = 100
t.MaxConnsPerHost = 100
t.MaxIdleConnsPerHost = 100

httpClient = &http.Client{
  Timeout:   10 * time.Second,
  Transport: t,
}

通過增加每個主機的連接數和空閑連接數,就有助於提高性能並以最少的服務器資源處理更多請求。

可以根據服務器資源和實際需求適當增加連接池大小和每個主機的連接數。

總結

這篇文章中,我們圍繞 net/http 包討論瞭默認配置的一些問題。通過更改 HTTP 客戶端的一些默認設置,在生產環境中也可以獲得高性能的 HTTP 客戶端。

到此這篇關於使用Go HTTP客戶端打造高性能服務的文章就介紹到這瞭,更多相關Go HTTP客戶端高性能內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: