最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

golang?熔斷器的實(shí)現(xiàn)過程

 更新時(shí)間:2022年01月26日 09:19:46   作者:運(yùn)維派  
這篇文章主要介紹了golang?熔斷器的實(shí)現(xiàn)過程,Go?項(xiàng)目中使用熔斷技術(shù)提高系統(tǒng)容錯(cuò)性。接下倆就來給打家介紹?go?熔斷器和其使用,需要的朋友可以參考一下

熔斷器像是一個(gè)保險(xiǎn)絲。當(dāng)我們依賴的服務(wù)出現(xiàn)問題時(shí),可以及時(shí)容錯(cuò)。一方面可以減少依賴服務(wù)對(duì)自身訪問的依賴,防止出現(xiàn)雪崩效應(yīng);另一方面降低請(qǐng)求頻率以方便上游盡快恢復(fù)服務(wù)。

熔斷器的應(yīng)用也非常廣泛。除了在我們應(yīng)用中,為了請(qǐng)求服務(wù)時(shí)使用熔斷器外,在 web 網(wǎng)關(guān)、微服務(wù)中,也有非常廣泛的應(yīng)用。本文將從源碼角度學(xué)習(xí) sony 開源的一個(gè)熔斷器實(shí)現(xiàn)

github/sony/gobreaker (代碼注釋可以從github/lpflpf/gobreaker查看)

1.熔斷器的模式

gobreaker 是基于《微軟云設(shè)計(jì)模式》一書中的熔斷器模式的 Golang 實(shí)現(xiàn)。有 sony 公司開源,目前 star 數(shù)有 1.2K。使用人數(shù)較多。

下面是模式定義的一個(gè)狀態(tài)機(jī):

熔斷器有三種狀態(tài),四種狀態(tài)轉(zhuǎn)移的情況:

  • 熔斷器關(guān)閉狀態(tài),服務(wù)正常訪問
  • 熔斷器開啟狀態(tài),服務(wù)異常
  • 熔斷器半開狀態(tài),部分請(qǐng)求限流訪問

四種狀態(tài)轉(zhuǎn)移:

  • 在熔斷器關(guān)閉狀態(tài)下,當(dāng)失敗后并滿足一定條件后,將直接轉(zhuǎn)移為熔斷器開啟狀態(tài)。
  • 在熔斷器開啟狀態(tài)下,如果過了規(guī)定的時(shí)間,將進(jìn)入半開啟狀態(tài),驗(yàn)證目前服務(wù)是否可用。
  • 在熔斷器半開啟狀態(tài)下,如果出現(xiàn)失敗,則再次進(jìn)入關(guān)閉狀態(tài)。
  • 在熔斷器半開啟后,所有請(qǐng)求(有限額)都是成功的,則熔斷器關(guān)閉。所有請(qǐng)求將正常訪問。

2.gobreaker 的實(shí)現(xiàn)

gobreaker 是在上述狀態(tài)機(jī)的基礎(chǔ)上,實(shí)現(xiàn)的一個(gè)熔斷器。

2.1熔斷器的定義

type CircuitBreaker struct { ?
? name ? ? ? ? ?string ?
? maxRequests ? uint32 ?// 最大請(qǐng)求數(shù) (半開啟狀態(tài)會(huì)限流) ?
? interval ? ? ?time.Duration ? // 統(tǒng)計(jì)周期 ?
? timeout ? ? ? time.Duration ? // 進(jìn)入熔斷后的超時(shí)時(shí)間 ?
? readyToTrip ? func(counts Counts) bool // 通過 Counts 判斷是否開啟熔斷。需要自定義 ?
? onStateChange func(name string, from State, to State) // 狀態(tài)修改時(shí)的鉤子函數(shù) ?

? mutex ? ? ?sync.Mutex // 互斥鎖,下面數(shù)據(jù)的更新都需要加鎖 ?
? state ? ? ?State ?// 記錄了當(dāng)前的狀態(tài) ?
? generation uint64 // 標(biāo)記屬于哪個(gè)周期 ?
? counts ? ? Counts // 計(jì)數(shù)器,統(tǒng)計(jì)了 成功、失敗、連續(xù)成功、連續(xù)失敗等,用于決策是否進(jìn)入熔斷 ?
? expiry ? ? time.Time // 進(jìn)入下個(gè)周期的時(shí)間 ?
} ?

其中,如下參數(shù)是我們可以自定義的:

  • MaxRequests:最大請(qǐng)求數(shù)。當(dāng)在最大請(qǐng)求數(shù)下,均請(qǐng)求正常的情況下,會(huì)關(guān)閉熔斷器
  • interval:一個(gè)正常的統(tǒng)計(jì)周期。如果為 0,那每次都會(huì)將計(jì)數(shù)清零
  • timeout: 進(jìn)入熔斷后,可以再次請(qǐng)求的時(shí)間
  • readyToTrip:判斷熔斷生效的鉤子函數(shù)
  • onStateChagne:狀態(tài)變更的鉤子函數(shù)

2.2請(qǐng)求的執(zhí)行

熔斷器的執(zhí)行操作,主要包括三個(gè)階段;①請(qǐng)求之前的判定;②服務(wù)的請(qǐng)求執(zhí)行;③請(qǐng)求后的狀態(tài)和計(jì)數(shù)的更新

// 熔斷器的調(diào)用 ?
func (cb *CircuitBreaker) Execute(req func() (interface{}, error)) (interface{}, error) { ?

? // ①請(qǐng)求之前的判斷 ?
? generation, err := cb.beforeRequest() ?
? if err != nil { ?
? ? return nil, err ?
? } ?

? defer func() { ?
? ? e := recover() ?
? ? if e != nil { ?
? ? ? // ③ panic 的捕獲 ?
? ? ? cb.afterRequest(generation, false) ?
? ? ? panic(e) ?
? ? } ?
? }() ?

? // ② 請(qǐng)求和執(zhí)行 ?
? result, err := req() ?

? // ③ 更新計(jì)數(shù) ?
? cb.afterRequest(generation, err == nil) ?
? return result, err ?
} ?

2.3請(qǐng)求之前的判定操作

請(qǐng)求之前,會(huì)判斷當(dāng)前熔斷器的狀態(tài)。如果熔斷器以開啟,則不會(huì)繼續(xù)請(qǐng)求。如果熔斷器半開,并且已達(dá)到最大請(qǐng)求閾值,也不會(huì)繼續(xù)請(qǐng)求。

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

? now := time.Now() ?
? state, generation := cb.currentState(now) ?

? if state == StateOpen { // 熔斷器開啟,直接返回 ?
? ? return generation, ErrOpenState ?
? } else if state == StateHalfOpen && cb.counts.Requests >= cb.maxRequests { // 如果是半打開的狀態(tài),并且請(qǐng)求次數(shù)過多了,則直接返回 ?
? ? return generation, ErrTooManyRequests ?
? } ?

? cb.counts.onRequest() ?
? return generation, nil ?
} ?

其中當(dāng)前狀態(tài)的計(jì)算,是依據(jù)當(dāng)前狀態(tài)來的。如果當(dāng)前狀態(tài)為已開啟,則判斷是否已經(jīng)超時(shí),超時(shí)就可以變更狀態(tài)到半開;如果當(dāng)前狀態(tài)為關(guān)閉狀態(tài),則通過周期判斷是否進(jìn)入下一個(gè)周期。

func (cb *CircuitBreaker) currentState(now time.Time) (State, uint64) { ?
? switch cb.state { ?
? case StateClosed: ?
? ? if !cb.expiry.IsZero() && cb.expiry.Before(now) { // 是否需要進(jìn)入下一個(gè)計(jì)數(shù)周期 ?
? ? ? cb.toNewGeneration(now) ?
? ? } ?
? case StateOpen: ?
? ? if cb.expiry.Before(now) { ?
? ? ? // 熔斷器由開啟變更為半開 ?
? ? ? cb.setState(StateHalfOpen, now) ?
? ? } ?
? } ?
? return cb.state, cb.generation ?
} ?

周期長度的設(shè)定,也是以據(jù)當(dāng)前狀態(tài)來的。如果當(dāng)前正常(熔斷器關(guān)閉),則設(shè)置為一個(gè) interval 的周期;如果當(dāng)前熔斷器是開啟狀態(tài),則設(shè)置為超時(shí)時(shí)間(超時(shí)后,才能變更為半開狀態(tài))。

2.4請(qǐng)求之后的處理操作

每次請(qǐng)求之后,會(huì)通過請(qǐng)求結(jié)果是否成功,對(duì)熔斷器做計(jì)數(shù)。

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

? now := time.Now() ?

? // 如果不在一個(gè)周期,就不再計(jì)數(shù) ?
? state, generation := cb.currentState(now) ?
? if generation != before { ?
? ? return ?
? } ?

? if success { ?
? ? cb.onSuccess(state, now) ?
? } else { ?
? ? cb.onFailure(state, now) ?
? } ?
} ?

如果在半開的狀態(tài)下:

如果請(qǐng)求成功,則會(huì)判斷當(dāng)前連續(xù)成功的請(qǐng)求數(shù) 大于等于 maxRequests, 則可以把狀態(tài)由半開狀態(tài)轉(zhuǎn)移為關(guān)閉狀態(tài)
如果在半開狀態(tài)下,請(qǐng)求失敗,則會(huì)直接將半開狀態(tài)轉(zhuǎn)移為開啟狀態(tài)
如果在關(guān)閉狀態(tài)下:

如果請(qǐng)求成功,則計(jì)數(shù)更新
如果請(qǐng)求失敗,則調(diào)用 readyToTrip 判斷是否需要將狀態(tài)關(guān)閉狀態(tài)轉(zhuǎn)移為開啟狀態(tài)

總結(jié):

  • 于頻繁請(qǐng)求一些遠(yuǎn)程或者第三方的不可靠的服務(wù),存在失敗的概率還是非常大的。使用熔斷器的好處就是可以是我們自身的服務(wù)不被這些不可靠的服務(wù)拖垮,造成雪崩。
  • 由于熔斷器里面,不僅會(huì)維護(hù)不少的統(tǒng)計(jì)數(shù)據(jù),還有互斥鎖做資源隔離,成本也會(huì)不少。
  • 在半開狀態(tài)下,可能出現(xiàn)請(qǐng)求過多的情況。這是由于半開狀態(tài)下,連續(xù)請(qǐng)求成功的數(shù)量未達(dá)到最大請(qǐng)求值。所以,熔斷器對(duì)于請(qǐng)求時(shí)間過長(但是比較頻繁)的服務(wù)可能會(huì)造成大量的 too many requests 錯(cuò)誤

到此這篇關(guān)于golang 熔斷器的實(shí)現(xiàn)過程的文章就介紹到這了,更多相關(guān)golang 熔斷器的實(shí)現(xiàn)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 使用go實(shí)現(xiàn)一個(gè)超級(jí)mini的消息隊(duì)列的示例代碼

    使用go實(shí)現(xiàn)一個(gè)超級(jí)mini的消息隊(duì)列的示例代碼

    本文主要介紹了使用go實(shí)現(xiàn)一個(gè)超級(jí)mini的消息隊(duì)列的示例代碼,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-12-12
  • Go實(shí)現(xiàn)并發(fā)緩存的示例代碼

    Go實(shí)現(xiàn)并發(fā)緩存的示例代碼

    高并發(fā)數(shù)據(jù)存儲(chǔ)是現(xiàn)代互聯(lián)網(wǎng)應(yīng)用開發(fā)中常遇到的一大挑戰(zhàn),本文主要介紹了Go實(shí)現(xiàn)并發(fā)緩存的示例代碼,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • Go語言中如何實(shí)現(xiàn)并發(fā)

    Go語言中如何實(shí)現(xiàn)并發(fā)

    Go的并發(fā)機(jī)制通過協(xié)程和通道的簡單性和高效性,使得編寫并發(fā)代碼變得相對(duì)容易,這種并發(fā)模型被廣泛用于構(gòu)建高性能的網(wǎng)絡(luò)服務(wù)、并行處理任務(wù)和其他需要有效利用多核處理器的應(yīng)用程序,這篇文章主要介紹了在Go中如何實(shí)現(xiàn)并發(fā),需要的朋友可以參考下
    2023-09-09
  • go-micro微服務(wù)domain層開發(fā)示例詳解

    go-micro微服務(wù)domain層開發(fā)示例詳解

    這篇文章主要為大家介紹了go-micro微服務(wù)domain層開發(fā)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-01-01
  • golang中net的tcp服務(wù)使用

    golang中net的tcp服務(wù)使用

    這篇文章主要介紹了golang中net的tcp服務(wù)使用,文章通過服務(wù)端監(jiān)聽端口 展開主題的詳細(xì)內(nèi)容,具有一定的參考價(jià)值,需要的 小伙伴可以參考一下
    2022-04-04
  • Go?1.22版本新特性前瞻

    Go?1.22版本新特性前瞻

    這篇文章主要為大家介紹了Go?1.22版本新特性前瞻,包含語言的變化,編譯器、運(yùn)行時(shí)與工具鏈等應(yīng)用對(duì)比詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2024-01-01
  • go?mongox簡潔高效文檔操作及bson數(shù)據(jù)構(gòu)造流暢技巧

    go?mongox簡潔高效文檔操作及bson數(shù)據(jù)構(gòu)造流暢技巧

    這篇文章主要為大家介紹了go?mongox簡潔高效文檔操作及bson數(shù)據(jù)構(gòu)造流暢技巧示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-11-11
  • Go strconv包實(shí)現(xiàn)字符串和基本數(shù)據(jù)類型轉(zhuǎn)換的實(shí)例詳解

    Go strconv包實(shí)現(xiàn)字符串和基本數(shù)據(jù)類型轉(zhuǎn)換的實(shí)例詳解

    在Go語言(Golang)的編程實(shí)踐中,strconv包是一個(gè)非常重要的標(biāo)準(zhǔn)庫,它提供了在基本數(shù)據(jù)類型(如整型、浮點(diǎn)型、布爾型)和字符串之間的轉(zhuǎn)換功能,本文給大家介紹了關(guān)于Go語言字符串轉(zhuǎn)換strconv,需要的朋友可以參考下
    2024-09-09
  • Golang源碼分析之golang/sync之singleflight

    Golang源碼分析之golang/sync之singleflight

    golang/sync庫拓展了官方自帶的sync庫,提供了errgroup、semaphore、singleflight及syncmap四個(gè)包,本次先分析第一個(gè)包errgroup的源代碼,下面這篇文章主要給大家介紹了關(guān)于Golang源碼分析之golang/sync之singleflight的相關(guān)資料,需要的朋友可以參考下
    2022-11-11
  • Go+Redis緩存設(shè)計(jì)與優(yōu)化實(shí)現(xiàn)

    Go+Redis緩存設(shè)計(jì)與優(yōu)化實(shí)現(xiàn)

    本文主要介紹了Go+Redis緩存設(shè)計(jì)與優(yōu)化實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2025-02-02

最新評(píng)論

文成县| 宁津县| 湘潭市| 莱阳市| 武汉市| 新邵县| 益阳市| 梧州市| 岳西县| 宁海县| 大余县| 深水埗区| 枣庄市| 梧州市| 林州市| 九台市| 津市市| 岱山县| 泰和县| 开阳县| 怀宁县| 上思县| 历史| 郁南县| 金湖县| 铁岭县| 岳阳市| 靖宇县| 虞城县| 锦屏县| 洛宁县| 万宁市| 山西省| 郑州市| 陕西省| 邓州市| 若羌县| 姜堰市| 马鞍山市| 夏邑县| 长汀县|