熔断器模式

最近看其他人的代码时,发现其使用了github.com/sony/gobreaker包,了解了下,这个是熔断器模式的golang版的实现,下面就说说自己对这个模式的理解。

当我们调用其他服务时,如果失败一般会抛出并记录异常或者重试再调用几次,这个熔断器模式就是用于这个场景的。在一些场景中,如果服务暂时不可用,如果全做重试处理,可能会加重服务端的负担,并且重试多次也会导致自己的服务页面的不可用,慢慢不可用的状态会扩散到更多服务。熔断器模式通过记录最近多次的请求结果,来判断当前要调用的服务是否正常,不过失败次数过多,则下次再请求这个服务时,不再请求直接返回失败。当过一段时间后,再少量尝试调用,如果这几次调用服务都可以正常返回,则解除限制。

这个处理方法,类似电路上的保险丝,如果服务多次不能正常提供服务,则暂停再去请求服务,待过一段时候后(给服务恢复留些时间),再尝试看看服务是不是好了,如果没好,重复等待、尝试,好了的话,就跟正常调用一样。

下面我们github.com/sony/gobreaker中是如何实现这个熔断器的。

熔断器对象:

type CircuitBreaker struct {
    name          string
    maxRequests   uint32
    interval      time.Duration
    timeout       time.Duration
    readyToTrip   func(counts Counts) bool
    onStateChange func(name string, from State, to State)

    mutex      sync.Mutex
    state      State
    generation uint64
    counts     Counts
    expiry     time.Time
}

熔断器状态

我们先说几个比较重要的字段,首先是 state 字段。

// State is a type that represents a state of CircuitBreaker.
type State int

// These constants are states of CircuitBreaker.
const (
    StateClosed State = iota
    StateHalfOpen
    StateOpen
)

熔断器运行中,有三种状态,分别是闭合状态、断开状态和半断开状态。

  • 闭合状态:也是最开始的状态,这个是时候,请求过来是,是可以正常处理的。如果服务多次失败,则进入到断开状态。
  • 断开状态:当服务不能正常提供服务时,则进入到该状态。并且熔断器每隔 timeout 时间段后,会切换到半断开状态,来再次看看服务是否已经恢复好了
  • 半断开状态:在这个状态时,允许一定(少量)调用服务,如果这次服务调用都正常返回,则切换到闭合状态。如果其中有失败,则再次切换到断开状态。

熔断器请求统计

熔断器用来记录请求成功、失败情况的计数字段

type Counts struct {
    Requests             uint32
    TotalSuccesses       uint32
    TotalFailures        uint32
    ConsecutiveSuccesses uint32
    ConsecutiveFailures  uint32
}

这个字段用来判断服务是否处于正常的状态,默认如果连续失败次数达到5次,则判断服务不可用,要切换到断开状态。判断服务是否可用,也可以 赋值 ReadyToTrip 字段,来自定义判断服务是否已经不正常了。

熔断器其他字段

  • Name 熔断器名字
  • MaxRequests 这个字段限制当熔断器处于半断开状态时,允许多少各请求尝试访问服务
  • interval 这个字段标示,当处于闭合状态时,每隔多久清零请求统计,如果为0,则不清零。
  • readyToTrip 当调用服务失败时,调用这个函数,会将当前的请求统计情况对象作为参数传入
  • onStateChange 当熔断器状态改变时调用这个函数
  • generation 状态每变化一次,该值增加一次如果这是了interval,则在闭合状态时,每隔interval时,也增加一次
  • expiry 设置超时时间点,比如当前是断开状态,何时到半断开状态

熔断器使用

说了这么多,到底怎么用呢?可以看下自带的示例

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "net/http"

    "github.com/sony/gobreaker"
)

var cb *gobreaker.CircuitBreaker

func init() {
    var st gobreaker.Settings
    st.Name = "HTTP GET"
    st.ReadyToTrip = func(counts gobreaker.Counts) bool {
        failureRatio := float64(counts.TotalFailures) / float64(counts.Requests)
        return counts.Requests >= 3 && failureRatio >= 0.6
    }

    cb = gobreaker.NewCircuitBreaker(st)
}

// Get wraps http.Get in CircuitBreaker.
func Get(url string) ([]byte, error) {
    body, err := cb.Execute(func() (interface{}, error) {
        resp, err := http.Get(url)
        if err != nil {
            return nil, err
        }

        defer resp.Body.Close()
        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            return nil, err
        }

        return body, nil
    })
    if err != nil {
        return nil, err
    }

    return body.([]byte), nil
}

func main() {
    body, err := Get("http://www.google.com/robots.txt")
    if err != nil {
        log.Fatal(err)
    }

    fmt.Println("%s", string(body))
}

先初始化一个熔断器,设置自定义的判断服务是否正常的函数,然后通过熔断器去调用服务,熔断器内部会记录每次调用是否成功,根据实际情况会转换自身的状态。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容