使用Go HTTP客戶端打造高性能服務(wù)
HTTP(超文本傳輸協(xié)議)是一種用于客戶端和服務(wù)器之間傳輸數(shù)據(jù)的通信協(xié)議。如果想要訪問服務(wù)器資源,HTTP 請(qǐng)求是必不可少的。Go 語言里,net/http 包附帶了默認(rèn)配置,我們可以適當(dāng)調(diào)整便可以獲得高性能。
大多數(shù)語言都有提供各自的 HTTP 客戶端,文章接下來部分我們將動(dòng)手實(shí)踐如何使用 Go 語言發(fā)起 HTTP 請(qǐng)求,并討論其中有可能遇到的問題。
在做 Go 項(xiàng)目時(shí),我就意識(shí)到 HTTP 客戶端如果配置不正確可能會(huì)隨時(shí)導(dǎo)致服務(wù)器崩潰。
在使用 HTTP Client 時(shí),我觀察到一些問題并總結(jié)出相應(yīng)的解決方案,如下所示:
問題一:默認(rèn)的 HTTP Client
默認(rèn)情況下,net/http 包自帶的 HTTP 客戶端不帶超時(shí)時(shí)間。如果你使用的是默認(rèn)的客戶端 http.DefaultClient(),這個(gè)是不帶超時(shí)時(shí)間的。
假如你請(qǐng)求外部的 API 掛了,發(fā)出的請(qǐng)求沒響應(yīng)導(dǎo)致連接一直出于打開狀態(tài)。隨著請(qǐng)求數(shù)越來越多,連接數(shù)隨之增加,導(dǎo)致耗盡服務(wù)器的資源,最后服務(wù)器隨之崩潰。
解決辦法:不要使用默認(rèn)的 HTTP 客戶端,根據(jù)實(shí)際情況設(shè)置超時(shí)時(shí)間。
var httpClient = &http.Client{ Timeout: time.Second * 10, }
對(duì)于 API 接口,超時(shí)時(shí)間建議不需要超過 10s,如果請(qǐng)求在 10s 內(nèi)沒有返回,則請(qǐng)求會(huì)取消并報(bào)錯(cuò):request canceled (Client.Timeout exceeded …) 。
問題二:默認(rèn)的 Http Transport
默認(rèn)情況下,HTTP 客戶端會(huì)維護(hù)一個(gè)連接池。當(dāng)請(qǐng)求完成之后,連接會(huì)保持打開狀態(tài)直到空閑時(shí)間超時(shí)(默認(rèn)是 90s)自動(dòng)斷開。如果有請(qǐng)求過來,會(huì)優(yōu)先使用已打開的連接而不是創(chuàng)建新的連接,請(qǐng)求完成之后,連接會(huì)返還到連接池中。
使用連接池將使用最少的服務(wù)器資源處理更多的 API 請(qǐng)求。
如果沒有自定義 HTTP 客戶端的 transport,將會(huì)使用默認(rèn)配置。
HTTP Transport 的默認(rèn)配置如下:
var DefaultTransport RoundTripper = &Transport{ ... MaxIdleConns: 100, IdleConnTimeout: 90 * time.Second, ... } const DefaultMaxIdleConnsPerHost = 2
MaxIdleConns 表示連接池大小,是可以打開的最大連接數(shù),默認(rèn)值是 100。
參數(shù) DefaultMaxIdleConnsPerHost 的默認(rèn)值是 2,表示每個(gè)主機(jī)(host)的打開連接數(shù)。這意味著,連接池中 100 個(gè)連接只有兩個(gè)連接分配給該主機(jī)。
隨著請(qǐng)求增多,但是只有兩個(gè)請(qǐng)求被處理,其他請(qǐng)求只能被迫等待并進(jìn)入 TIME_WAIT 狀態(tài)。請(qǐng)求增多,進(jìn)入 TIME_WAIT 狀態(tài)的連接數(shù)增多,消耗越來越多的服務(wù)器資源,當(dāng)達(dá)到服務(wù)器瓶頸時(shí),服務(wù)器將會(huì)崩潰。
解決辦法:提高 MaxIdleConnsPerHost 數(shù)值,不要使用默認(rèn)的 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, }
通過增加每個(gè)主機(jī)的連接數(shù)和空閑連接數(shù),就有助于提高性能并以最少的服務(wù)器資源處理更多請(qǐng)求。
可以根據(jù)服務(wù)器資源和實(shí)際需求適當(dāng)增加連接池大小和每個(gè)主機(jī)的連接數(shù)。
總結(jié)
這篇文章中,我們圍繞 net/http 包討論了默認(rèn)配置的一些問題。通過更改 HTTP 客戶端的一些默認(rèn)設(shè)置,在生產(chǎn)環(huán)境中也可以獲得高性能的 HTTP 客戶端。
到此這篇關(guān)于使用Go HTTP客戶端打造高性能服務(wù)的文章就介紹到這了,更多相關(guān)Go HTTP客戶端高性能內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
深入淺出Golang中select的實(shí)現(xiàn)原理
在go語言中,select語句就是用來監(jiān)聽和channel有關(guān)的IO操作,當(dāng)IO操作發(fā)生時(shí),觸發(fā)相應(yīng)的case操作,有了select語句,可以實(shí)現(xiàn)main主線程與goroutine線程之間的互動(dòng)。本文就來詳細(xì)講講select的實(shí)現(xiàn)原理,需要的可以參考一下2022-08-08一文帶你了解Golang中reflect反射的常見錯(cuò)誤
go?反射的錯(cuò)誤大多數(shù)都來自于調(diào)用了一個(gè)不適合當(dāng)前類型的方法,?而且,這些錯(cuò)誤通常是在運(yùn)行時(shí)才會(huì)暴露出來,而不是在編譯時(shí),如果我們傳遞的類型在反射代碼中沒有被覆蓋到那么很容易就會(huì)?panic。本文就介紹一下使用?go?反射時(shí)很大概率會(huì)出現(xiàn)的錯(cuò)誤,需要的可以參考一下2023-01-01Golang學(xué)習(xí)筆記之安裝Go1.15版本(win/linux/macos/docker安裝)
這篇文章主要介紹了Golang學(xué)習(xí)筆記之安裝Go1.15版本(win/linux/macos/docker安裝),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12關(guān)于升級(jí)go1.18的goland問題詳解
作為一個(gè)go語言程序員,覺得自己有義務(wù)為go新手開一條更簡單便捷的上手之路,下面這篇文章主要給大家介紹了關(guān)于升級(jí)go1.18的goland問題的相關(guān)資料,需要的朋友可以參考下2022-11-11Golang利用channel協(xié)調(diào)協(xié)程的方法詳解
go?當(dāng)中的并發(fā)編程是通過goroutine來實(shí)現(xiàn)的,利用channel(管道)可以在協(xié)程之間傳遞數(shù)據(jù),所以本文就來講講Golang如何利用channel協(xié)調(diào)協(xié)程吧2023-05-05Go語言基礎(chǔ)函數(shù)包的使用學(xué)習(xí)
本文通過一個(gè)實(shí)現(xiàn)加減乘除運(yùn)算的小程序來介紹go函數(shù)的使用,以及使用函數(shù)的注意事項(xiàng),并引出了對(duì)包的了解和使用,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-05-05