Golang 实现熔断机制

开发 后端
一些场景下,为了保障服务稳定性会引入熔断机制。本文介绍了用 Go 语言自己实现熔断需要什么操作。

 一些场景下,为了保障服务稳定性会引入熔断机制。本文介绍了用 Go 语言自己实现熔断需要什么操作。

什么是熔断?

熔断是指在下游发生错误时上游主动关闭或限制对下游的请求。

原理

  1.  通常熔断器分为三个时期:CLOSED,OPEN,HALFOPEN
  2.  RPC 正常时,为 CLOSED;
  3.  当 RPC 错误增多时,熔断器会被触发,进入 OPEN;
  4.  OPEN 后经过一定的冷却时间,熔断器变为 HALFOPEN;
  5.  HALFOPEN 时会对下游进行一些有策略的访问,然后根据结果决定是变为 CLOSED,还是 OPEN;

总得来说三个状态的转换大致如下图:

Go 实现

https://github.com/rubyist/circuitbreaker

IsAllowed 是否允许请求,根据当前状态判断

CLOSE 允许

OPEN

  •  在 CoolingTimeout 冷却时间内,不允许
  •  过了冷却时间,状态变为 HALFOPEN,允许访问

HALFOPEN

  •  在 DetectTimeout 检测时间内,允许访问
  •  否则不允许

atomic.StoreInt32((*int32)(&b.state), int32(HALFOPEN))

trip 判断是否达到熔断限额(可以自定义)

type TripFunc func(Metricser) bool 
  • 1.
  •  ThresholdTripFunc 错误阈值
  •  ConsecutiveTripFunc 连续错误超过阈值
  •  RateTripFunc 根据最少访问数和错误率判断

Metricser 访问统计,包括成功数、失败数、超时数、错误率、采样数、连续错误数 

type Metricser interface {  
   Fail()    // records a failure  
   Succeed() // records a success  
   Timeout() // records a timeout  
   Failures() int64    // return the number of failures  
   Successes() int64   // return the number of successes  
   Timeouts() int64    // return the number of timeouts  
   ConseErrors() int64 // return the consecutive errors recently  
   ErrorRate() float64 // rate = (timeouts + failures) / (timeouts + failures + successes)  
   Samples() int64     // (timeouts + failures + successes)  
   Counts() (successes, failures, timeouts int64)  
   Reset()  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.

window 实现类 

type window struct {  
   sync.RWMutex  
   oldest  int32     // oldest bucket index  
   latest  int32     // latest bucket index  
   buckets []bucket // buckets this window holds  
   bucketTime time.Duration // time each bucket holds  
   bucketNums int32         // the numbe of buckets  
   inWindow   int32         // the number of buckets in the window  
   allSuccess int64  
   allFailure int64  
   allTimeout int64  
   conseErr int64  
 
type bucket struct {  
   failure int64  
   success int64  
   timeout int64  

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

用环形队列实现动态统计。把一个连续的时间切成多个小份,每一个 bucket 保存 BucketTime 的统计数据,BucketTime * BucketNums 是统计的时间区间。

每 BucketTime,会有一个 bucket 过期 

if w.inWindow == w.bucketNums {  
   // the lastest covered the oldest(latest == oldest)  
   oldBucket := &w.buckets[w.oldest]  
   atomic.AddInt64(&w.allSuccess, -oldBucket.Successes())  
   atomic.AddInt64(&w.allFailure, -oldBucket.Failures())  
   atomic.AddInt64(&w.allTimeout, -oldBucket.Timeouts())  
   w.oldest++  
   if w.oldest >= w.bucketNums {  
      w.oldest = 0  
   }  
} else {  
   w.inWindow++  
 
w.latest++ 
if w.latest >= w.bucketNums {  
   w.latest = 0  
 
(&w.buckets[w.latest]).Reset() 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

Panel Metricser 的容器

PanelStateChangeHandler 熔断事件 

type PanelStateChangeHandler func(key string, oldState, newState State, m Metricser) 
  • 1.

缺陷

  1.  所有 breaker 公用同一个 BucketTime,统计周期不支持更新
  2.  冷却时间不支持动态更新 

 

责任编辑:庞桂玉 来源: 马哥Linux运维
相关推荐

2021-11-25 09:55:47

Golang熔断器语言

2021-07-22 09:43:09

Golang语言并发机制

2021-02-22 11:30:07

Golang 1.16ModuleGolang

2020-09-26 10:56:33

服务器熔断服务隔离

2022-07-05 09:44:25

服务治理熔断限流

2022-08-08 08:31:00

Linux内存管理

2022-12-28 08:08:57

2025-02-27 08:00:00

熔断机制微服务Spring

2025-02-27 09:35:22

2022-08-26 10:24:48

架构Golang

2022-05-17 12:23:25

排序算法面试

2025-04-09 11:15:00

服务熔断服务降分布式系统

2022-01-17 10:55:50

微服务API网关

2020-07-28 08:32:57

微服务API网关熔断

2022-11-16 17:16:41

spring限流

2024-10-09 17:19:04

GoGolangKubernetes

2024-11-12 08:00:00

LSM树GolangMemTable

2023-01-26 00:59:39

B-Treegolang度量衡

2023-07-03 07:40:13

VueGolangweb

2023-11-14 08:38:43

Golang人脸识别
点赞
收藏

51CTO技术栈公众号