欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

go-zero過載保護源碼解讀

 更新時間:2023年08月10日 11:11:51   作者:TTSimple  
這篇文章主要為大家介紹了go-zero過載保護源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

引言

在看文章之前可以看看萬總的這篇文章《服務自適應降載保護設計》,文章已經給我們介紹很清楚了,從基礎原理到架構需求再到代碼注釋,無不細致入微,感謝萬總。

之前在設計架構的時候對于服務過載保護只會想到在客戶端、網關層來實現(xiàn),沒考慮過在服務端也可以達到這種效果,一來涉及這種技術的文章較少(可能是我孤陋寡聞了),二來服務端不確定的情況比較多,比如服務器出現(xiàn)問題,或者其他在同一臺服務器運行的軟件把服務器直接搞掛,這樣在服務端實現(xiàn)過載保護在某些層面來說魯棒性可能不太好 ,但在和熔斷器結合后,用服務端來實現(xiàn)過載保護也是合情合理的。

我們來看下過載保護設計到的幾個算法

自旋鎖

  • 原理

問:假設有1個變量lock,2個協(xié)程怎么用鎖實現(xiàn)lock++,lock的結果最后為2

答:

  • 鎖也是1個變量,初值設為0;
  • 1個協(xié)程將鎖原子性的置為1;
  • 操作變量lock;
  • 操作完成后,將鎖原子性的置為0,釋放鎖。
  • 在1個協(xié)程獲取鎖時,另一個協(xié)程一直嘗試,直到能夠獲取鎖(不斷循環(huán)),這就是自旋鎖。

自旋鎖的缺點

  • 某個協(xié)程持有鎖時間長,等待的協(xié)程一直在循環(huán)等待,消耗CPU資源。
  • 不公平,有可能存在有的協(xié)程等待時間過程,出現(xiàn)線程饑餓(這里就是協(xié)程饑餓)

go-zero 自旋鎖源碼

type SpinLock struct {
    // 鎖變量
    lock uint32
}
// Lock locks the SpinLock.
func (sl *SpinLock) Lock() {
    for !sl.TryLock() {
        // 暫停當前goroutine,讓其他goroutine先行運算
        runtime.Gosched()
    }
}
// TryLock tries to lock the SpinLock.
func (sl *SpinLock) TryLock() bool {
    // 原子交換,0換成1
    return atomic.CompareAndSwapUint32(&sl.lock, 0, 1)
}
// Unlock unlocks the SpinLock.
func (sl *SpinLock) Unlock() {
    // 原子置零
    atomic.StoreUint32(&sl.lock, 0)
}

源碼中還使用了 golang 的運行時操作包 runtime

runtime.Gosched()暫停當前goroutine,讓其他goroutine先行運算

注意:只是暫停,不是掛起。

當時間片輪轉到該協(xié)程時,Gosched()后面的操作將自動恢復

我們來寫寫幾行代碼,看看他的作用是啥

func output(s string) {
    for i := 0; i < 3; i++ {
        fmt.Println(s)
    }
}
// 未使用Gosched的代碼
func Test_GoschedDisable(t *testing.T) {
    go output("goroutine 2")
    output("goroutine 1")
}
// === RUN   Test_GoschedDisable
// goroutine 1
// goroutine 1
// goroutine 1
// --- PASS: Test_GoschedDisable (0.00s)

小結

還沒等到子協(xié)程執(zhí)行,主協(xié)程就已經執(zhí)行完退出了,子協(xié)程將不再執(zhí)行,所以打印的全部是主協(xié)程的數(shù)據(jù)。當然,實際上這個執(zhí)行結果也是不確定的,只是大概率出現(xiàn)以上輸出,因為主協(xié)程和子協(xié)程間并沒有絕對的順序關系

func output(s string) {
    for i := 0; i < 3; i++ {
        fmt.Println(s)
    }
}
// 使用Gosched的代碼
func Test_GoschedEnable(t *testing.T) {
    go output("goroutine 2")
    runtime.Gosched()
    output("goroutine 1")
}
// === RUN   Test_GoschedEnable
// goroutine 2
// goroutine 2
// goroutine 2
// goroutine 1
// goroutine 1
// goroutine 1
// --- PASS: Test_GoschedEnable (0.00s)

結論:在打印goroutine 1之前,主協(xié)程調用了runtime.Gosched()方法,暫停了主協(xié)程。子協(xié)程獲得了調度,從而先行打印了goroutine 2。主協(xié)程不是一定要等其他協(xié)程執(zhí)行完才會繼續(xù)執(zhí)行,而是一定時間。如果這個時間內其他協(xié)程沒有執(zhí)行完,那么主協(xié)程將繼續(xù)執(zhí)行,例如以下例子

func output(s string) {
    for i := 0; i < 3; i++ {
        fmt.Println(s)
    }
}
// 使用Gosched的代碼,并故意延長子協(xié)程的執(zhí)行時間,看主協(xié)程是否一直等待
func Test_GoschedEnableAndSleep(t *testing.T) {
    go func() {
        time.Sleep(5000)
        output("goroutine 2")
    }()
    runtime.Gosched()
    output("goroutine 1")
}
// === RUN   Test_GoschedEnableAndSleep
// goroutine 2
// goroutine 2
// goroutine 2
// goroutine 1
// goroutine 1
// goroutine 1
// --- PASS: Test_GoschedEnableAndSleep (0.00s)

結論:即使我們故意延長子協(xié)程的執(zhí)行時間,主協(xié)程還是會一直等待子協(xié)程執(zhí)行完才會執(zhí)行。

源碼中還使用了 golang 的原子操作包 atomic

atomic.CompareAndSwapUint32()函數(shù)用于對uint32值執(zhí)行比較和交換操作,此函數(shù)是并發(fā)安全的。

// addr 表示地址
// old  表示uint32值,它是舊的,
// new  表示uint32新值,它將與舊值交換自身。
// 如果交換完成,則返回true,否則返回false。
func CompareAndSwapUint32(addr *uint32, old, new uint32) (swapped bool)

atomic.StoreUint32() 函數(shù)用于將val原子存儲到* addr中,此函數(shù)是并發(fā)安全的。

// addr 表示地址
// val  表示uint32值,它是舊的,
func StoreUint32(addr *uint32, val uint32)

過載保護核心還使用了滑動窗口,滑動窗口的原理和細節(jié)可以看前一篇文章,里面有詳細解答。

以上就是go-zero過載保護源碼解讀的詳細內容,更多關于go-zero過載保護的資料請關注腳本之家其它相關文章!

相關文章

  • golang實現(xiàn)大文件上傳功能全過程

    golang實現(xiàn)大文件上傳功能全過程

    Go語言可以用來實現(xiàn)大文件傳輸,下面這篇文章主要給大家介紹了關于golang實現(xiàn)大文件上傳功能的相關資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-07-07
  • go語言結構體指針操作示例詳解

    go語言結構體指針操作示例詳解

    這篇文章主要為大家介紹了go語言結構體指針操作示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步早日升職加薪
    2022-04-04
  • 一文搞懂Golang?值傳遞還是引用傳遞

    一文搞懂Golang?值傳遞還是引用傳遞

    最多人犯迷糊的就是?slice、map、chan?等類型,都會認為是?“引用傳遞”,從而認為?Go?語言的?xxx?就是引用傳遞。正因為它們還引用類型(指針、map、slice、chan等這些),這樣就可以修改原內容數(shù)據(jù),這篇文章主要介紹了Golang?值傳遞還是引用傳遞,需要的朋友可以參考下
    2023-01-01
  • 詳解golang 定時任務time.Sleep和time.Tick實現(xiàn)結果比較

    詳解golang 定時任務time.Sleep和time.Tick實現(xiàn)結果比較

    本文主要介紹了golang 定時任務time.Sleep和time.Tick實現(xiàn)結果比較,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-02-02
  • 深入分析Go?實現(xiàn)?MySQL?數(shù)據(jù)庫事務

    深入分析Go?實現(xiàn)?MySQL?數(shù)據(jù)庫事務

    本文深入分析了Go語言實現(xiàn)MySQL數(shù)據(jù)庫事務的原理和實現(xiàn)方式,包括事務的ACID特性、事務的隔離級別、事務的實現(xiàn)方式等。同時,本文還介紹了Go語言中的事務處理機制和相關的API函數(shù),以及如何使用Go語言實現(xiàn)MySQL數(shù)據(jù)庫事務。
    2023-06-06
  • Golang內存泄露場景與定位方式的實現(xiàn)

    Golang內存泄露場景與定位方式的實現(xiàn)

    Golang有自動垃圾回收機制,但是仍然可能會出現(xiàn)內存泄漏的情況,本文主要介紹了Golang內存泄露場景與定位方式的實現(xiàn),具有一定的參考價值,感興趣的可以了解一下
    2024-04-04
  • Go語言入門之函數(shù)的定義與使用

    Go語言入門之函數(shù)的定義與使用

    函數(shù)是一段代碼的片段,包含連續(xù)的執(zhí)行語句,它可以將零個或多個輸入參數(shù)映射到零個或多個參數(shù)輸出。本文將通過示例和大家詳細聊聊Go語言中函數(shù)的定義與使用,感興趣的可以了解一下
    2022-11-11
  • GO中的時間操作總結(time&dateparse)

    GO中的時間操作總結(time&dateparse)

    日常開發(fā)過程中,對于時間的操作可謂是無處不在,但是想實現(xiàn)時間自由還是不簡單的,多種時間格式容易混淆,本文為大家整理了一下GO中的時間操作,有需要的可以參考下
    2023-09-09
  • Go語言使用釘釘機器人推送消息的實現(xiàn)示例

    Go語言使用釘釘機器人推送消息的實現(xiàn)示例

    本文主要介紹了Go語言使用釘釘機器人推送消息的實現(xiàn)示例,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • Golang切片連接成字符串的實現(xiàn)示例

    Golang切片連接成字符串的實現(xiàn)示例

    本文主要介紹了Golang切片連接成字符串的實現(xiàn)示例,可以使用Go語言中的內置函數(shù)"String()"可以將字節(jié)切片轉換為字符串,具有一定的參考價值,感興趣的可以了解一下
    2023-11-11

最新評論