重試工具 — retry-go
編輯推薦:Bazinga
簡介
在微服務架構中,通常會有很多的小服務,小服務之間存在大量 RPC 呼叫,但時常因為網路抖動等原因,造成請求失敗,這時候使用重試機制可以提高請求的最終成功率,減少故障影響,讓系統執行更穩定。retry-go 是一個功能比較完善的 golang 重試庫。
如何使用:
retry-go
的使用非常簡單,直接使用 Do
方法即可。如下是一個發起 HTTP Get 請求的重試示例 :
url := "https://gocn.vip"
var body []byte
err := retry.Do(
func() error {
resp, err := http.Get(url)
if err != nil {
return err
}
defer resp.Body.Close()
body, err = ioutil.ReadAll(resp.Body)
if err != nil {
return err
}
return nil
},
)
fmt.Println(body)
呼叫時,有一些可選的配置項:
- attempts 最大重試次數
- delay 重試延遲時間
- maxDelay 最大重試延遲時間,選擇指數退避策略時,該配置會限制等待時間上限
- maxJitter 隨機退避策略的最大等待時間
- onRetry 每次重試時進行的一次回撥
- retryIf 重試時的一個條件判斷
- delayType 退避策略型別
- lastErrorOnly 是否只返回上次重試的錯誤
BackOff 退避策略
對於一些暫時性的錯誤,如網路抖動等,立即重試可能還是會失敗,通常等待一小會兒再重試的話成功率會較高,並且這種策略也可以打散上游重試的時間,避免同時重試而導致的瞬間流量高峰。決定等待多久之後再重試的方法叫做退避策略。retry-go
實現了以下幾個退避策略:
func BackOffDelay
func BackOffDelay(n uint, _ error, config *Config) time.Duration
BackOffDelay 提供一個指數避退策略,連續重試時,每次等待時間都是前一次的 2 倍。
func FixedDelay
func FixedDelay(_ uint, _ error, config *Config) time.Duration
FixedDelay 在每次重試時,等待一個固定延遲時間。
func RandomDelay
func RandomDelay(_ uint, _ error, config *Config) time.Duration
RandomDelay 在 0 - config.maxJitter 內隨機等待一個時間後重試。
func CombineDelay
func CombineDelay(delays ...DelayTypeFunc) DelayTypeFunc
CombineDelay 提供結合多種策略實現一個新策略的能力。
retry-go
預設的退避策略為 BackOffDelay
和RandomDelay
結合的方式,即在指數遞增的同時,加一個隨機時間。
自定義的延時策略
下面是一個官方給出的例子,當請求的響應有Retry-After
頭時,使用該值去進行等待,其他情況按照 BackOffDelay 策略進行延時等待。
var _ error = (*RetriableError)(nil)
func test2(){
var body []byte
err := retry.Do(
func() error {
resp, err := http.Get("URL")
if err == nil {
defer func() {
if err := resp.Body.Close(); err != nil {
panic(err)
}
}()
body, err = ioutil.ReadAll(resp.Body)
if resp.StatusCode != 200 {
err = fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body))
if resp.StatusCode == http.StatusTooManyRequests {
// check Retry-After header if it contains seconds to wait for the next retry
if retryAfter, e := strconv.ParseInt(resp.Header.Get("Retry-After"), 10, 32); e == nil {
// the server returns 0 to inform that the operation cannot be retried
if retryAfter <= 0 {
return retry.Unrecoverable(err)
}
return &RetriableError{
Err: err,
RetryAfter: time.Duration(retryAfter) * time.Second,
}
}
// A real implementation should also try to http.Parse the retryAfter response header
// to conform with HTTP specification. Herein we know here that we return only seconds.
}
}
}
return err
},
retry.DelayType(func(n uint, err error, config *retry.Config) time.Duration {
fmt.Println("Server fails with: " + err.Error())
if retriable, ok := err.(*RetriableError); ok {
fmt.Printf("Client follows server recommendation to retry after %v\n", retriable.RetryAfter)
return retriable.RetryAfter
}
// apply a default exponential back off strategy
return retry.BackOffDelay(n, err, config)
}),
)
fmt.Println("Server responds with: " + string(body))
}
總結
重試可以提升服務呼叫的成功率,但重試時也要警惕由此帶來的放大故障的風險。選擇合適的退避策略,控制放大效應,才能優雅的提升服務的穩定性。
Reference
更多原創文章乾貨分享,請關注公眾號
- 加微信實戰群請加微信(註明:實戰群):gocnio
相關文章
- Go小工具系列——重試機制Go
- 軟體測試工具與測試思想孰重孰輕
- 重試/retrying/retry/重試控制機制
- RabbitMQ重試機制MQ
- [測試工具]
- 【工具】ORION I/O 測試工具
- 介面測試工具
- 安全測試工具
- 【DNS】測試工具DNS
- 測試工具集合
- 效能測試工具
- 程式碼重構與單元測試——重構1的單元測試(四)
- 軟體測試工具之開源測試工具彙總
- .NET重構—單元測試的程式碼重構
- TestNG測試框架之失敗測試重跑框架
- 重試利器之Guava RetryingGuava
- zuul超時及重試配置Zuul
- Python重試模組retryingPython
- RocketMQ(5)---RocketMQ重試機制MQ
- Guava Retryer實現介面重試Guava
- Python錯誤重試方法Python
- 重試利器之Guava-RetryerGuava
- 移動app測試重點APP
- Spring Retry重試機制Spring
- 測試去除重複資料
- 【工具】基準測試工具之sysbench
- websocket線上測試工具Web
- 單元測試工具
- 測試工具-XPath使用
- 效能測試工具Locust
- mysqlslap 效能測試工具MySql
- 軟體測試工具
- RESTful測試工具 RESTClientRESTclient
- 壓力測試工具
- 安全測試工具收集
- 效能測試工具supersmackMac
- 使用猴子測試工具
- 介面測試工具-PostmanPostman