真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

微服務的斷路器實現(xiàn)圖解Golang通用實現(xiàn)

斷路器背景

微服務連鎖故障場景

微服務的斷路器實現(xiàn)圖解Golang通用實現(xiàn)
在分布式環(huán)境中,各個微服務相互調(diào)用,當某些情況下,比如后端中間件服務故障、第三方服務中斷導致某個服務無限期不可用,短時間無法恢復,則可能會導致連鎖故障,最終影響壓垮整個業(yè)務集群

成都創(chuàng)新互聯(lián)主要從事網(wǎng)站設計制作、成都做網(wǎng)站、網(wǎng)頁設計、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務。立足成都服務察隅,10多年網(wǎng)站建設經(jīng)驗,價格優(yōu)惠、服務專業(yè),歡迎來電咨詢建站服務:18980820575

斷路器與重試

斷路器模式不同于重試模式,重試模式是使應用程序可以重試操作以期望它會成功,而斷路器模式是防止應用程序執(zhí)行一個可能失敗的操作,減少執(zhí)行可能失敗操作的CPU、內(nèi)存、線程等資源的浪費,從而保證服務的整體可用

斷路器設計解析

基于代理模式的斷路器

微服務的斷路器實現(xiàn)圖解Golang通用實現(xiàn)
斷路器相當于一個請求操作執(zhí)行的代理,托管請求操作的執(zhí)行

實現(xiàn)原理流程:

  1. 攔截服務執(zhí)行的請求,通過當前狀態(tài)決定是否直接返回,如果否則執(zhí)行后續(xù)操作
  2. 嘗試執(zhí)行操作,并獲取返回結果
  3. 根據(jù)返回結果和當前統(tǒng)計信息,決定當前斷路器的狀態(tài),修改狀態(tài)
  4. 返回執(zhí)行結果

斷路器狀態(tài)機

微服務的斷路器實現(xiàn)圖解Golang通用實現(xiàn)
斷路器狀態(tài)機實現(xiàn)上有三種狀態(tài):Closed(斷路器關閉)、Open(開放)、HalfOpen(半開放)

狀態(tài)說明備注
Closed 關閉 斷路器關閉正常執(zhí)行操作
Open 打開 斷路器開放,所有請求直接返回錯誤,不執(zhí)行任何請求
HalfOpen 半開放 允許有限數(shù)量的請求通過,如果執(zhí)行成功,恢復到關閉狀態(tài),如果仍然失敗,則恢復到開放,然后重新啟動超時定時器

#斷路器實現(xiàn)

實現(xiàn)原理圖解

微服務的斷路器實現(xiàn)圖解Golang通用實現(xiàn)
斷路器實現(xiàn)實現(xiàn)主要分為三部分:狀態(tài)統(tǒng)計、狀態(tài)轉(zhuǎn)移、請求執(zhí)行

狀態(tài)統(tǒng)計:統(tǒng)計已經(jīng)執(zhí)行的請求的成功失敗的數(shù)量,以確定是否需要進行狀態(tài)轉(zhuǎn)移
狀態(tài)轉(zhuǎn)移:根據(jù)當前統(tǒng)計信息和當前狀態(tài)來進行目標狀態(tài)的確定及轉(zhuǎn)移操作
請求執(zhí)行:代理前端任務的執(zhí)行,如果當前狀態(tài)不需要進行嘗試執(zhí)行,就直接返回錯誤,避免資源浪費

Golang里面已經(jīng)有開源的實現(xiàn),https://github.com/sony/gobreaker/blob/, 接下來救市剖析它的實現(xiàn)

狀態(tài)統(tǒng)計-計數(shù)器Counts

Counts就是一個計數(shù)器,記錄當前請求成功和失敗的數(shù)量

type Counts struct {
    Requests             uint32    // 請求數(shù)
    TotalSuccesses       uint32    // 成功
    TotalFailures        uint32    // 失敗
    ConsecutiveSuccesses uint32    // 連續(xù)成功
    ConsecutiveFailures  uint32 // 連續(xù)失敗
}

計數(shù)器完成對應請求狀態(tài)的次數(shù),為后續(xù)狀態(tài)轉(zhuǎn)移提供數(shù)據(jù), Counts提供了onRequest、onSuccess、onFailure、clear幾個輔助接口用于實現(xiàn)對應請求狀態(tài)的操作,感興趣可以看下

狀態(tài)機- CircuitBreaker

type CircuitBreaker struct {
    name          string
        // maxRequests限制half-open狀態(tài)下最大的請求數(shù),避免海量請求將在恢復過程中的服務再次失敗
    maxRequests   uint32
     // interval用于在closed狀態(tài)下,斷路器多久清除一次Counts信息,如果設置為0則在closed狀態(tài)下不會清除Counts
    interval      time.Duration
        // timeout進入open狀態(tài)下,多長時間切換到half-open狀態(tài),默認60s
    timeout       time.Duration
        // readyToTrip熔斷條件,當執(zhí)行失敗后,會根據(jù)readyToTrip決定是否進入Open狀態(tài)
    readyToTrip   func(counts Counts) bool
        // onStateChange斷路器狀態(tài)變更回調(diào)函數(shù)
    onStateChange func(name string, from State, to State)

    mutex      sync.Mutex
        //. state 斷路器狀態(tài)
    state      State
        // generation 是一個遞增值,相當于當前斷路器狀態(tài)切換的次數(shù), 為了避免狀態(tài)切換后,未完成請求對新狀態(tài)的統(tǒng)計的影響,如果發(fā)現(xiàn)一個請求的generation同當前的generation不同,則不會進行統(tǒng)計計數(shù)
    generation uint64
        //  Counts 統(tǒng)計
    counts     Counts
        // expiry 超時過期用于open狀態(tài)到half-open狀態(tài)的切換,當超時后,會從open狀態(tài)切換到half-open狀態(tài)
    expiry     time.Time
}

核心流程

CircuitBreaker.Execute

請求執(zhí)行,對外開放的請求執(zhí)行接口

func (cb *CircuitBreaker) Execute(req func() (interface{}, error)) (interface{}, error) {
        // 執(zhí)行請求鉤子,會根據(jù)當前狀態(tài),來返回當前的generation和err(如果位于open和half-open則不為nil), 通過err來進行判斷是否直接返回
    generation, err := cb.beforeRequest()
    if err != nil {
        return nil, err
    }

        // 捕獲panic,避免應用函數(shù)錯誤造成斷路器panic
    defer func() {
        e := recover()
        if e != nil {
            cb.afterRequest(generation, false)
            panic(e)
        }
    }()

    // 執(zhí)行請求
    result, err := req()
        // 根據(jù)結果來進行對應狀態(tài)的統(tǒng)計, 同時傳遞generation
    cb.afterRequest(generation, err == nil)
    return result, err
}

CircuitBreaker.beforeRequest

func (cb *CircuitBreaker) beforeRequest() (uint64, error) {
    cb.mutex.Lock()
    defer cb.mutex.Unlock()

        // 獲取當前的狀態(tài)
    now := time.Now()
    state, generation := cb.currentState(now)

    // open和half-open狀態(tài)則直接返回
    if state == StateOpen {
        return generation, ErrOpenState
    } else if state == StateHalfOpen && cb.counts.Requests >= cb.maxRequests {
            // 避免海量請求對處于恢復服務的影響,這里有一個限流的操作,避免請求數(shù)超過最大請求數(shù)
        return generation, ErrTooManyRequests
    }
        // 統(tǒng)計狀態(tài)
    cb.counts.onRequest()
    return generation, nil
}

CircuitBreaker.afterRequest

func (cb *CircuitBreaker) afterRequest(before uint64, success bool) {
    cb.mutex.Lock()
    defer cb.mutex.Unlock()

    // 重新獲取狀態(tài)
    now := time.Now()
    state, generation := cb.currentState(now)
        // 如果前后狀態(tài)不一致,則不計數(shù)
    if generation != before {
        return
    }

        // 根據(jù)狀態(tài)計數(shù)
    if success {
        cb.onSuccess(state, now)
    } else {
        cb.onFailure(state, now)
    }
}

CircuitBreaker.currentState

func (cb *CircuitBreaker) currentState(now time.Time) (State, uint64) {
    switch cb.state {
    case StateClosed:
                // 如果當前當前是closed狀態(tài),并且有設置expiry,則遞增Generation到新一輪統(tǒng)計計數(shù)
        if !cb.expiry.IsZero() && cb.expiry.Before(now) {
            cb.toNewGeneration(now)
        }
    case StateOpen:
                // 如果是Open狀態(tài),并且超時,則嘗試到半打開狀態(tài)
        if cb.expiry.Before(now) {
            cb.setState(StateHalfOpen, now)
        }
    }
    return cb.state, cb.generation
}

CircuitBreaker.toNewgeneration

func (cb *CircuitBreaker) toNewGeneration(now time.Time) {
        // 遞增generation, 清除狀態(tài)
    cb.generation++
    cb.counts.clear()

        // 設置超時時間
    var zero time.Time
    switch cb.state {
    case StateClosed:
        if cb.interval == 0 {
            cb.expiry = zero
        } else {
            cb.expiry = now.Add(cb.interval)
        }
    case StateOpen:
        cb.expiry = now.Add(cb.timeout)
    default: // StateHalfOpen
        cb.expiry = zero
    }
}

總結

斷路器黃金鏈路

微服務的斷路器實現(xiàn)圖解Golang通用實現(xiàn)

  • beforeRequest :完成當前請求是否可以執(zhí)行請求,狀態(tài)超時切換,同時返回當前的genenration
  • req: 執(zhí)行請求
  • afterRequest: 完成請求狀態(tài)統(tǒng)計,決定狀態(tài)切換

斷路器的優(yōu)缺點

斷路器比較適合針對遠程服務或者第三方服務的調(diào)用,如果該操作極有可能會失敗,則斷路器可以盡可能的減小失敗對應用的影響,避免資源浪費

但缺點也顯而易見,斷路器本身相當于一層代理,在應用程序執(zhí)行進行統(tǒng)計和控制,本身就有一定的資源消耗,同時內(nèi)部基于synx.Mutex鎖來實現(xiàn),高并發(fā)下肯定會有鎖爭用問題,可能需要根據(jù)業(yè)務來使用多個斷路器,來分散這種鎖爭用,同時應該避免在斷路器req函數(shù)內(nèi),去執(zhí)行重試和過長時間的超時等待,因為斷路器核心是快速失敗

更多文章可以訪問http://www.sreguide.com/


新聞名稱:微服務的斷路器實現(xiàn)圖解Golang通用實現(xiàn)
瀏覽路徑:http://weahome.cn/article/pccdes.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部