溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

golang中怎么實現(xiàn)一個熔斷器

發(fā)布時間:2021-07-20 15:16:01 來源:億速云 閱讀:429 作者:Leah 欄目:編程語言

本篇文章給大家分享的是有關(guān)golang中怎么實現(xiàn)一個熔斷器,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

對目前開源熔斷器的對比

熔斷器名稱hystrixgo-breaker
滑動窗口計數(shù)支持不支持
限流支持不支持
阻塞讀
對半開啟的處理滑動計數(shù)器+閾值連續(xù)成功則轉(zhuǎn)移到close
對監(jiān)控的支持支持metric采集不支持
降級處理支持hook支持hook
解決并發(fā)尖刺不支持支持
代碼結(jié)構(gòu)易讀性稍差較好

我們一一展開來講

計數(shù)模塊

計數(shù)模塊是熔斷器的核心,網(wǎng)上有針對計數(shù)器的大篇幅的分析針對這里引用知乎上一位大佬的比較類型的文章,根據(jù)最后的比較我們選擇滑動窗口的算法來完成計數(shù)需求。 在hystrix的設(shè)計中,滑動窗口的比較重要的是寫入時刻和讀取時刻,因為我們很容易想到在這兩個環(huán)節(jié)涉及到對一塊內(nèi)存并發(fā)讀寫的問題,首先我們不建議采用go-breaker的全加鎖(讀寫都加鎖)的設(shè)計,因為鎖在發(fā)生競爭時會掛起線程,從而降低了CPU的使用率和共享內(nèi)存總線上的同步通信量,那么我們參考hystrix,采用異步提交的方法,也就是將結(jié)果放入一個隊列中,不斷消費這個隊列,這么做有幾點好處

消息串行化,減少寫入讀取數(shù)據(jù)不必要競爭
在數(shù)據(jù)生產(chǎn)層--->數(shù)據(jù)存儲層中間構(gòu)造出中間層,方便進行監(jiān)控統(tǒng)計收集等操作
方便控制消息的消費情況

在實現(xiàn)上采用channel的數(shù)據(jù)結(jié)構(gòu),消費有高效保證。但是事物都有兩面性,這種設(shè)計帶來的問題有

滑動窗口統(tǒng)計需要訪問當前窗口內(nèi)所有數(shù)據(jù)
串行化沒有將統(tǒng)計性能發(fā)揮最大(雖然在計數(shù)豐方面表現(xiàn)很快)
業(yè)務(wù)要允許流量尖刺的出現(xiàn)(假設(shè)沒有加限流)

其中2,3點經(jīng)過調(diào)研都在業(yè)務(wù)允許范圍內(nèi),且針對第三點我們可以增加限流策略來完善這一點。 golang中怎么實現(xiàn)一個熔斷器

限流

hystrix天生限流,所有請求先過令牌桶然后進入熔斷統(tǒng)計,go-breaker還沒有這方面支持,在限流這里我們懷疑要不要在一起做(畢竟熔斷是熔斷,限流是限流),所以做了另一個方案,在半開啟時進行限流放行請求,這樣比較符合半開啟時的請求通過策略,同時進行統(tǒng)計,限流策略采用退化版本令牌桶,方法如下:

type limitPoolManager struct {
	max     int
	tickets chan *struct{}
	lock    *sync.RWMutex
}

/*
方法返回一個限流器
*/
func NewLimitPoolManager(max int) *limitPoolManager {
	lpm := new(limitPoolManager)
	tickets := make(chan *struct{}, max)
	for i := 0; i < max; i++ {
		tickets <- &struct{}{}
	}
	lpm.max = max
	lpm.tickets = tickets
	lpm.lock = &sync.RWMutex{}
	return lpm
}

/*
方法填充限流器所有令牌
*/
func (this *limitPoolManager) ReturnAll() {
	this.lock.Lock()
	defer this.lock.Unlock()
	if len(this.tickets) == 0 {
		for i := 0; i < this.max; i++ {
			this.tickets <- &struct{}{}
		}
	}
}

/*
方法返回一個令牌,得到令牌返回true,令牌用完后返回false
*/
func (this *limitPoolManager) GetTicket() bool {
	this.lock.RLock()
	defer this.lock.RUnlock()
	select {
	case <-this.tickets:
		return true
	default:
		return false
	}
}

/*
方法返回剩余令牌數(shù)
*/
func (this *limitPoolManager) GetRemaind() int {
	this.lock.RLock()
	defer this.lock.RUnlock()
	return len(this.tickets)
}

阻塞讀

因為串行化設(shè)計所以在每次收失敗請求時可以對窗口內(nèi)數(shù)據(jù)進行錯誤率轉(zhuǎn)化。避免hystrix與go-breaker的鎖爭搶

半開啟處理

以上+本節(jié)主流程基本完結(jié),現(xiàn)梳理整個流程明確half-open時處理:

當熔斷器為close時。只有當出現(xiàn)錯誤請求時,才進行錯誤率統(tǒng)計,統(tǒng)計過閾值則狀態(tài)轉(zhuǎn)移到open,正確請求則正常計數(shù)。
當熔斷器為half-open時,僅當令牌桶中還有令牌時接收請求否則熔斷。令牌桶中還有令牌時,出現(xiàn)錯誤請求則更新熔斷休眠時間并返回所有令牌等待下次半開啟,正常請求則進入半開啟時統(tǒng)計達到閾值則狀態(tài)轉(zhuǎn)移到close。
當熔斷器為open時,僅當熔斷休眠時間小于當前時間時,當熔斷器狀態(tài)轉(zhuǎn)移到half-open,可以進行第二條,否則執(zhí)行熔斷

首先判斷是否是半開啟狀態(tài)

switch this.counter.GetStatus() {
	case STATE_OPEN:
		if this.cycleTime < time.Now().Local().Unix() {
			return OPEN_TO_HALF_ERROR
		}
		return BREAKER_OPEN_ERROR
	}

其次如果是半開啟狀態(tài)則取令牌,取到令牌則執(zhí)行請求,進入熔斷時計數(shù),否則直接熔斷

/*取令牌*/
		if !this.lpm.GetTicket() {
			this.safelCalllback(fallback, BREAKER_OPEN_ERROR)
			return nil
		}
		/*執(zhí)行方法*/
		runErr := run()
		if runErr != nil {
			this.fail()
			this.safelCalllback(fallback, runErr)
			return runErr
		}
		this.success()
		return nil

流量尖刺處理

流量尖刺的削峰伴隨著限流的邏輯,所以可以在請求到達時優(yōu)先進入令牌桶

監(jiān)控&降級

提供hook函數(shù),在限流或者執(zhí)行失敗時可以提供降級或者回掉

/*
執(zhí)行函數(shù)
*/
type runFunc func() error

/*
回調(diào)函數(shù)
*/
type fallbackFunc func(error)

/*
Do方法結(jié)合熔斷策略執(zhí)行run函數(shù)
其中參數(shù)包括:上下文ctx,策略名name,將要執(zhí)行方法run,以及回調(diào)函數(shù)fallback.其中ctx,name,run必傳
run函數(shù)的錯誤會直接同步返回,回調(diào)函數(shù)fallback接收除了run錯誤以外還會接收熔斷時錯誤,調(diào)用方如果需要降級可在fallback中自己判斷
*/
func Do(ctx context.Context, name string, run runFunc, fallback fallbackFunc) error {
........
}

以上就是golang中怎么實現(xiàn)一個熔斷器,小編相信有部分知識點可能是我們?nèi)粘9ぷ鲿姷交蛴玫降?。希望你能通過這篇文章學到更多知識。更多詳情敬請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI