图解 Go 微服务中的熔断器和重试( 二 )

demo 中分别测试了请求调用链 closed 和 open 两种情况:
/* Experiment 1: success path */// servergo run main.go// clientfor i in $(seq 10); do curl -x '' localhost:8080 ;done/* Experiment 2: circuit open */// serverSERVER_ERROR=1 Go run main.go// clientfor i in $(seq 10); do curl -x '' localhost:8080 ;done查看源码
重试问题在上面的熔断器模式中,如果服务 B 缩容,会发生什么?大量已经从 A 发出的请求会返回 5xx error 。可能会触发熔断器切换到 open 的错误报警 。因此我们需要重试以防间歇性的 network hiccup 发生 。
一段简单的重试代码示例:
package mainfunc callWithRetryV1() (err error) { for index := 0; index < 3; index++ {  // call producer API  err := callChargeProducerAPI()  if err != nil {   return err  } } // adding backoff // adding jitter return nil}查看源码
重试模式为了实现乐观锁,我们可以为不同的服务配置不同的重试次数 。因为立即重试会对下游服务产生爆发性的请求,所以不能用立即重试 。加一个 backoff 时间可以缓解下游服务的压力 。一些其他的模式会用一个随机的 backoff 时间(或在等待时加 jitter) 。
一起来看下列算法:

  • Exponential: bash * 2attemp
  • Full Jitter: sleep = rand(0, base * 2attempt)
  • Equal Jitter: temp = base * 2attemp; sleep = temp/2+rand(0, temp/2)
  • De-corredlated Jitter: sleep = rand(base, sleep*3)
【译注】关于这几个算法,可以参考这篇文章。Full Jitter、 Equal Jitter、 De-corredlated 等都是原作者自己定义的名词 。
图解 Go 微服务中的熔断器和重试

文章插图
 
05
客户端的数量与服务端的总负载和处理完成时间是有关联的 。为了确定什么样的重试模式最适合你的系统,在客户端数量增加时很有必要运行基准测试 。详细的实验过程可以在这篇文章中看到 。我建议的算法是 de-corredlated Jitter 和 full jitter 选择其中一个 。
两者结合
图解 Go 微服务中的熔断器和重试

文章插图
 
Example configuration of both tools
【图解 Go 微服务中的熔断器和重试】熔断器被广泛用在无状态线上事务系统中,尤其是在聚合点上 。重试应该用于调度作业或不被 timeout 约束的 worker 。经过深思熟虑后我们可以同时用熔断器和重试 。在大型系统中,service mesh 是一种能更精确地编排不同配置的理想架构 。
参考文章
  1. https://github.com/afex/hystrix-go/
  2. https://github.com/eApache/go-resiliency
  3. https://github.com/Netflix/Hystrix/wiki
  4. https://www.awsarchitectureblog.com/2015/03/backoff.html
  5. https://dzone.com/articles/go-microservices-part-11-hystrix-and-resilience


推荐阅读