В микросервисной архитектуре обычно имеется множество небольших сервисов и большое количество RPC вызов,Но часто из-за таких причин, как тряска сети,вызывая сбой запроса,В настоящее время использование механизма повтора может повысить окончательную вероятность успеха запроса.,Уменьшите последствия сбоев,Сделайте работу системы более стабильной。retry-go Это относительно полная функция golang Повторите попытку библиотеки.
go get https://github.com/avast/retry-go
Использовать retry-go очень просто, просто используйте метод Do напрямую. Ниже приведен пример повтора запроса HTTP Get:
url := "http://example.com"
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)
При вызове есть несколько дополнительных элементов конфигурации:
В случае некоторых временных ошибок, таких как дрожание сети и т. д., немедленная повторная попытка все равно может оказаться неудачной. Обычно вероятность успеха будет выше, если вы подождите некоторое время и повторите попытку, и эта стратегия также может сократить время повтора восходящего потока. Избегайте мгновенных всплесков трафика, вызванных одновременными повторными попытками. Метод принятия решения о том, как долго ждать перед повторной попыткой, называется стратегией отсрочки. retry-go реализует следующие стратегии отсрочки:
func BackOffDelay(n uint, _ error, config *Config) time.Duration
BackOffDelay обеспечивает экспоненциальную стратегию отсрочки. При непрерывных повторных попытках каждое время ожидания в два раза дольше предыдущего.
func FixedDelay(_ uint, _ error, config *Config) time.Duration
Фиксированная задержка Ожидает фиксированного времени задержки при каждой повторной попытке.
func RandomDelay(_ uint, _ error, config *Config) time.Duration
RandomDelay ожидает случайное время в пределах 0 — config.maxJitter перед повторной попыткой.
func CombineDelay(delays ...DelayTypeFunc) DelayTypeFunc
JointDelay предоставляет возможность комбинировать несколько стратегий для реализации новой стратегии.
Стратегия отсрочки повтора по умолчанию представляет собой комбинацию 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))
}
Повторная попытка может повысить вероятность успеха сервисных вызовов, но вы также должны опасаться риска увеличения числа неудач при повторной попытке. Только выбрав подходящую стратегию отсрочки и контролируя эффект усиления, можно элегантно улучшить стабильность сервиса.