建设网站视频百度云盘,营销型网站的特征,济南网络营销策划公司,成都政务网站建设文章目录 概要一、服务熔断二、断路器模式三、hystrix-go3.1、使用3.2、源码 四、参考 概要
微服务先行者Martin Fowler与James Lewis在文章microservices中指出了微服务的九大特征#xff0c;其中一个便是容错性设计(Design for failure)。正如文章中提到的#xff0c;微服… 文章目录 概要一、服务熔断二、断路器模式三、hystrix-go3.1、使用3.2、源码 四、参考 概要
微服务先行者Martin Fowler与James Lewis在文章microservices中指出了微服务的九大特征其中一个便是容错性设计(Design for failure)。正如文章中提到的微服务相对于单体服务而言不同服务之间的通信是经过网络完成的服务间调用时上游服务可能随时处于不可用状态比如崩溃达到服务最大处理能力等等原因。 由此会引发一个问题一个服务点的错误经过层层传递最终会波及到调用链上的所有服务这便是雪崩效应因此如何防止雪崩效应便是微服务架构容错性设计原则的具体实践否则服务化程度越高整个系统反而越不稳定。 在实践中有很多容错方案诸如故障转移、快速失败服务熔断、安全失败、沉默失败、故障恢复、负载均衡、重试、限流、服务降级、舱壁隔离等等。这些方案分别从事前(负载均衡、限流、舱壁隔离、服务降级)事中故障转移、快速失败、安全失败、沉默失败、重试事后故障恢复三个节点提高整个系统的稳定性。
PS:服务降级归到事前主要是因为服务降级大多数情况下不是在出现错误后才被执行的在许多场景中所说的服务降级更多的是指需要主动使服务进入降级逻辑的情况比如电商预见双11流量高峰、游戏停服更新等。
一、服务熔断
服务熔断策略方案来源于生活中的电路保险丝电路保险丝遵循一家一个的原则当该家庭电流增大到一定数值时其自身熔断而切断电路保护电视机、冰箱等电器并不会影响其他家庭的用电。
同理可推理到微服务之间的网络调用。 如图当服务C出现异常构服务B很快会检测到服务C不可用服务C接口超时或错误等指标满足不可用判定条件此时服务B不在将请求转发到服务C,而是快速返回错误信息快速失败。在一段时间内的后续请求就一直返回失败稍后当检测到服务C接口调用响应正常后就会恢复到正常状态。
二、断路器模式
断路器模式是实现熔断策略的具体方案其本质是接管微服务之间的远程调用请求断路器会持续监控并统计被调用服务接口返回成功、失败、超时、拒绝等各种结果的指标当某一个指标满足预设阈值时断路器就会进入开启状态后续相应的远程调用请求就会快速返回错误信息而不会真的对被调用服务发起请求。若干时间后断路器会进入半打开状态此时断路器会放行一次请求如果请求正常则断路器进入关闭状态否则转入开启状态。
从上面描述来看断路器是一种有限状态机
关闭状态此时断路器会放行请求到上游服务该状态是断路器的初始状态开启状态当断路器统计的某一项指标满足开启条件时就会进入该状态此时不会放行请求到上游服务而是快速返回错误信息半打开状态这时一种中间状态主要是因为断路器要具有故障恢复的能力所以当进入该状态时断路器会允许放行一次请求到上游服务。一般是在断路器开启后若干时间后自动进入该状态。 断路器进入半打开状态在实现时并不需要计时器而是收到请求时检测下是否满足半打开状态一般是将断路器开启时间与当前时间做比较是的话就放行该次请求否则快速返回错误信息。 断路器工作时序图如下
三、hystrix-go
hystrix-go是作者从JAVA Netflix的子项目Hystrix翻译过来的很经典的断路器项目。
3.1、使用
hystrix-go 调用接口有两个
Do同步调用
func Do(name string, run runFunc, fallback fallbackFunc)Go异步调用
func Go(name string, run runFunc, fallback fallbackFunc)hystrix-go配置项
// CommandConfig is used to tune circuit settings at runtime
type CommandConfig struct {Timeout int json:timeoutMaxConcurrentRequests int json:max_concurrent_requestsRequestVolumeThreshold int json:request_volume_thresholdSleepWindow int json:sleep_windowErrorPercentThreshold int json:error_percent_threshold
}MaxConcurrentRequests请求的并发量接口并发超过该值也会被归为接口错误ErrMaxConcurrencyTimeout请求超时时间接口响应时间超过该值也会归为接口错误(ErrTimeout)RequestVolumeThreshold一个窗口代码里写死的10秒内的请求数阙值达到这个阙值才会进入接口错误百分比计算逻辑ErrorPercentThreshold 设置接口错误(除了ErrMaxConcurrencyErrTimeout两种错误接口自身错误也会被计入)的百分比大于该值断路器就会进入开启状态SleepWindow断路器开启后多久后进入半开启状态。
直接上代码。
import (errorsfmtgithub.com/afex/hystrix-go/hystrixtime
)
var (global errortimes int
)
//模拟远程请求
func mockHttp() error {timesfmt.Println(times)if global ! nil {return nil}time.Sleep(2 * time.Second)return errors.New(业务出错)
}
const breakFlag testBreaker
func main() {hystrix.ConfigureCommand(breakFlag, hystrix.CommandConfig{Timeout: 1000, MaxConcurrentRequests: 50, ErrorPercentThreshold: 25, RequestVolumeThreshold: 4, SleepWindow: 1000, })//hystrix.SetLogger() //打印断流器内部日志for i : 0; i 10; i {time.Sleep(time.Millisecond * 400) //给熔断器重试服务时机_ hystrix.Do(breakFlag, func() error {return mockHttp()}, func(err error) error { //不发生错误不会进入该逻辑的if err ! nil {fmt.Printf(times:%d,断路器检测到错误%s\n, times, err.Error())} else {fmt.Printf(times:%d,断路器恢复正常, times)}global errreturn nil})}fmt.Println(times:, times)
}输出如下
1
times:1,断路器检测到错误hystrix: timeout
2
3
4
times:4,断路器检测到错误hystrix: circuit open
times:4,断路器检测到错误hystrix: circuit open
times:4,断路器检测到错误hystrix: circuit open
5
6
7
times: 7分析 可以看到真正发出的请求是7次3次是被快速失败了
第一次请求接口超时第四次请求时10s内的请求4个了满足RequestVolumeThreshold配置此时错误接口个数是1,计算1/4*100等于25不小于ErrorPercentThreshold配置断路器进入开启状态第五、六、七次的请求都被快速失败了第八次请求时满足断路器进入半开启状态的条件time.Millisecond * 400*3SleepWindow,放行本次请求并且请求响应正常那么断路器进入关闭状态第九、十次正常。
3.2、源码
Do和Go两个API最终都会进入GoC函数
func GoC(ctx context.Context, name string, run runFuncC, fallback fallbackFuncC) chan error {cmd : command{run: run,fallback: fallback,start: time.Now(),errChan: make(chan error, 1),finished: make(chan bool, 1),}circuit, _, err : GetCircuit(name)//获取指标统计器if err ! nil {cmd.errChan - errreturn cmd.errChan}cmd.circuit circuitticketCond : sync.NewCond(cmd)ticketChecked : falsereturnTicket : func() {cmd.Lock()// Avoid releasing before a ticket is acquired.for !ticketChecked {ticketCond.Wait()}cmd.circuit.executorPool.Return(cmd.ticket)//执行完之后归还请求令牌cmd.Unlock()}// Shared by the following two goroutines. It ensures only the faster// goroutine runs errWithFallback() and reportAllEvent().returnOnce : sync.Once{}reportAllEvent : func() {err : cmd.circuit.ReportEvent(cmd.events, cmd.start, cmd.runDuration)//上报此次请求时正常还是异常便于后续进行指标统计if err ! nil {log.Printf(err.Error())}}go func() {defer func() { cmd.finished - true }()if !cmd.circuit.AllowRequest() {//统计指标决定开启、半开启、关闭三个状态的流转cmd.Lock()// Its safe for another goroutine to go ahead releasing a nil ticket.ticketChecked trueticketCond.Signal()cmd.Unlock()returnOnce.Do(func() {returnTicket()cmd.errorWithFallback(ctx, ErrCircuitOpen)//上报断路器处于开启状态的错误不过该错误不会被纳入接口错误指标reportAllEvent()})return}cmd.Lock()select {case cmd.ticket -circuit.executorPool.Tickets://获取一个请求令牌ticketChecked trueticketCond.Signal()cmd.Unlock()default: //没有令牌就表示请求达到并发限制MaxConcurrentRequests配置的值上报ErrMaxConcurrency错误ticketChecked trueticketCond.Signal()cmd.Unlock()returnOnce.Do(func() {returnTicket()cmd.errorWithFallback(ctx, ErrMaxConcurrency)reportAllEvent()})return}runStart : time.Now()runErr : run(ctx) //没有达到限流就发起请求returnOnce.Do(func() {defer reportAllEvent()cmd.runDuration time.Since(runStart)returnTicket()if runErr ! nil {cmd.errorWithFallback(ctx, runErr) //出错就上报业务接口的错误return}cmd.reportEvent(success)//表示请求成功})}()go func() {timer : time.NewTimer(getSettings(name).Timeout)//根据Timeout配置起一个定时器defer timer.Stop()select {case -cmd.finished: //请求执行完毕// returnOnce has been executed in another goroutinecase -ctx.Done(): //收集context上下文错误returnOnce.Do(func() {returnTicket()cmd.errorWithFallback(ctx, ctx.Err())reportAllEvent()})returncase -timer.C: //标识服务接口超时上报ErrTimeout错误returnOnce.Do(func() {returnTicket()cmd.errorWithFallback(ctx, ErrTimeout)reportAllEvent()})return}}()return cmd.errChan
}进入开启状态
func (circuit *CircuitBreaker) AllowRequest() bool {return !circuit.IsOpen() || circuit.allowSingleTest()
}
//判断断路器处于关闭状态还是开启状态
func (circuit *CircuitBreaker) IsOpen() bool {circuit.mutex.RLock()o : circuit.forceOpen || circuit.opencircuit.mutex.RUnlock()if o {return true}if uint64(circuit.metrics.Requests().Sum(time.Now())) getSettings(circuit.Name).RequestVolumeThreshold {return false}if !circuit.metrics.IsHealthy(time.Now()) {//计算10s内错误请求百分比// too many failures, open the circuitcircuit.setOpen() //断路器状态为开启状态return true}return false
}//circuit.metrics.Requests().Sum方法这里可以看到统计指标的窗口是10s
func (r *Number) Sum(now time.Time) float64 {sum : float64(0)r.Mutex.RLock()defer r.Mutex.RUnlock()for timestamp, bucket : range r.Buckets {// TODO: configurable rolling windowif timestamp now.Unix()-10 {sum bucket.Value}}return sum
}断路器半开启状态判断
func (circuit *CircuitBreaker) allowSingleTest() bool {circuit.mutex.RLock()defer circuit.mutex.RUnlock()now : time.Now().UnixNano()openedOrLastTestedTime : atomic.LoadInt64(circuit.openedOrLastTestedTime)//如果断路器处于开启状态且当前时间断路器开启时间SleepWindow配置精确到纳秒则进入半开启状态if circuit.open now openedOrLastTestedTimegetSettings(circuit.Name).SleepWindow.Nanoseconds() {swapped : atomic.CompareAndSwapInt64(circuit.openedOrLastTestedTime, openedOrLastTestedTime, now)if swapped {log.Printf(hystrix-go: allowing single test to possibly close circuit %v, circuit.Name)}return swapped}return false
}恢复为关闭状态
func (circuit *CircuitBreaker) ReportEvent(eventTypes []string, start time.Time, runDuration time.Duration) error {if len(eventTypes) 0 {return fmt.Errorf(no event types sent for metrics)}circuit.mutex.RLock()o : circuit.opencircuit.mutex.RUnlock()if eventTypes[0] success o {//此次请求成功且断路器处于开启状态则将断路器转为关闭状态circuit.setClose()}//省略代码...return nil
}四、参考
1]:服务治理熔断器介绍以及hystrix-go的使用 2]:Microservices 文章转载自: http://www.morning.hjssh.cn.gov.cn.hjssh.cn http://www.morning.mmhyx.cn.gov.cn.mmhyx.cn http://www.morning.cwznh.cn.gov.cn.cwznh.cn http://www.morning.bnbtp.cn.gov.cn.bnbtp.cn http://www.morning.qhfdl.cn.gov.cn.qhfdl.cn http://www.morning.rhkmn.cn.gov.cn.rhkmn.cn http://www.morning.nbgfz.cn.gov.cn.nbgfz.cn http://www.morning.srbl.cn.gov.cn.srbl.cn http://www.morning.mqbsm.cn.gov.cn.mqbsm.cn http://www.morning.kttbx.cn.gov.cn.kttbx.cn http://www.morning.spftz.cn.gov.cn.spftz.cn http://www.morning.qwrb.cn.gov.cn.qwrb.cn http://www.morning.jkdtz.cn.gov.cn.jkdtz.cn http://www.morning.ytfr.cn.gov.cn.ytfr.cn http://www.morning.mmynk.cn.gov.cn.mmynk.cn http://www.morning.bzlfw.cn.gov.cn.bzlfw.cn http://www.morning.nhdw.cn.gov.cn.nhdw.cn http://www.morning.qhmql.cn.gov.cn.qhmql.cn http://www.morning.qtzwh.cn.gov.cn.qtzwh.cn http://www.morning.ndngj.cn.gov.cn.ndngj.cn http://www.morning.ygrdb.cn.gov.cn.ygrdb.cn http://www.morning.rhgtc.cn.gov.cn.rhgtc.cn http://www.morning.ljxps.cn.gov.cn.ljxps.cn http://www.morning.sjbpg.cn.gov.cn.sjbpg.cn http://www.morning.kqyyq.cn.gov.cn.kqyyq.cn http://www.morning.fykrm.cn.gov.cn.fykrm.cn http://www.morning.brbmf.cn.gov.cn.brbmf.cn http://www.morning.pbygt.cn.gov.cn.pbygt.cn http://www.morning.wslr.cn.gov.cn.wslr.cn http://www.morning.lhjmq.cn.gov.cn.lhjmq.cn http://www.morning.lnwdh.cn.gov.cn.lnwdh.cn http://www.morning.qkqhr.cn.gov.cn.qkqhr.cn http://www.morning.txlnd.cn.gov.cn.txlnd.cn http://www.morning.nfpct.cn.gov.cn.nfpct.cn http://www.morning.qlbmc.cn.gov.cn.qlbmc.cn http://www.morning.rmtxp.cn.gov.cn.rmtxp.cn http://www.morning.nggry.cn.gov.cn.nggry.cn http://www.morning.fnrkh.cn.gov.cn.fnrkh.cn http://www.morning.fcftj.cn.gov.cn.fcftj.cn http://www.morning.rwjtf.cn.gov.cn.rwjtf.cn http://www.morning.jzlfq.cn.gov.cn.jzlfq.cn http://www.morning.hhxwr.cn.gov.cn.hhxwr.cn http://www.morning.wlnr.cn.gov.cn.wlnr.cn http://www.morning.fnmgr.cn.gov.cn.fnmgr.cn http://www.morning.wfspn.cn.gov.cn.wfspn.cn http://www.morning.wgbmj.cn.gov.cn.wgbmj.cn http://www.morning.zlhbg.cn.gov.cn.zlhbg.cn http://www.morning.ltcnd.cn.gov.cn.ltcnd.cn http://www.morning.csnmd.cn.gov.cn.csnmd.cn http://www.morning.supera.com.cn.gov.cn.supera.com.cn http://www.morning.kdrjd.cn.gov.cn.kdrjd.cn http://www.morning.qrnbs.cn.gov.cn.qrnbs.cn http://www.morning.ccphj.cn.gov.cn.ccphj.cn http://www.morning.lnwdh.cn.gov.cn.lnwdh.cn http://www.morning.rpsjh.cn.gov.cn.rpsjh.cn http://www.morning.nhzzn.cn.gov.cn.nhzzn.cn http://www.morning.qhtlq.cn.gov.cn.qhtlq.cn http://www.morning.rzsxb.cn.gov.cn.rzsxb.cn http://www.morning.qglqb.cn.gov.cn.qglqb.cn http://www.morning.nlkhr.cn.gov.cn.nlkhr.cn http://www.morning.qbtkg.cn.gov.cn.qbtkg.cn http://www.morning.qzqjz.cn.gov.cn.qzqjz.cn http://www.morning.yrccw.cn.gov.cn.yrccw.cn http://www.morning.mpszk.cn.gov.cn.mpszk.cn http://www.morning.jxscp.cn.gov.cn.jxscp.cn http://www.morning.gkpgj.cn.gov.cn.gkpgj.cn http://www.morning.ffwrq.cn.gov.cn.ffwrq.cn http://www.morning.fglth.cn.gov.cn.fglth.cn http://www.morning.mtmnk.cn.gov.cn.mtmnk.cn http://www.morning.rgpy.cn.gov.cn.rgpy.cn http://www.morning.rnrwq.cn.gov.cn.rnrwq.cn http://www.morning.fslxc.cn.gov.cn.fslxc.cn http://www.morning.dpmkn.cn.gov.cn.dpmkn.cn http://www.morning.qqnjr.cn.gov.cn.qqnjr.cn http://www.morning.ljpqy.cn.gov.cn.ljpqy.cn http://www.morning.tzzfy.cn.gov.cn.tzzfy.cn http://www.morning.wjwfj.cn.gov.cn.wjwfj.cn http://www.morning.hxhrg.cn.gov.cn.hxhrg.cn http://www.morning.sjwzz.cn.gov.cn.sjwzz.cn http://www.morning.w58hje.cn.gov.cn.w58hje.cn