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

Go?實(shí)現(xiàn)?Nginx?加權(quán)輪詢算法的方法步驟

 更新時(shí)間:2021年12月08日 11:33:30   作者:一只小蝸牛  
本文主要介紹了Go?實(shí)現(xiàn)?Nginx?加權(quán)輪詢算法的方法步驟,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

最近在看一些 getway 相關(guān)的資料,發(fā)現(xiàn)有關(guān) Nginx 負(fù)載均衡的算法有點(diǎn)多,但是有點(diǎn)亂,所以整理下。。。如有不對地方請指出。

一,Nginx 負(fù)載均衡的輪詢 (round-robin)

在說加權(quán)輪詢之前我們先來簡單的說一下輪詢

1. nginx 中的配置

upstream cluster {
    server 192.168.0.14;
    server 192.168.0.15;
}

location / {
   proxy_set_header X-Real-IP $remote_addr;               //返回真實(shí)IP
   proxy_pass http://cluster;                           //代理指向cluster 
    
}

2. 簡單介紹

輪詢 作為負(fù)載均衡中較為基礎(chǔ)的算法,他的實(shí)現(xiàn)不需要配置額外的參數(shù)。簡單理解:配置文件中一共配置了 N 臺服務(wù)器,輪詢 算法會遍歷服務(wù)的節(jié)點(diǎn)列表,并按照節(jié)點(diǎn)順序每輪選擇一臺服務(wù)器處理請求,當(dāng)所有節(jié)點(diǎn)遍歷一遍后,重新開始

3. 特點(diǎn)

輪詢 算法中我們不難看出,每臺服務(wù)器處理請求的數(shù)量基本持平,按照請求時(shí)間逐一分配,因此只能適用于集群服務(wù)器性能相近的情況,平均分配讓每臺服務(wù)器承載量基本持平。但是如果集群服務(wù)器性能參差不齊,這樣的算法會導(dǎo)致資源分配不合理,造成部分請求阻塞,部分服務(wù)器資源浪費(fèi)。為了解決上述問題,我們將 輪詢 算法升級了,引入了 加權(quán)輪詢 算法,讓集群中性能差異較大的服務(wù)器也能合理分配資源。達(dá)到資源盡量最大化合理利用

4. 實(shí)現(xiàn) (這里使用golang模擬實(shí)現(xiàn))

type RoundRobinBalance struct {
    curIndex int
    rss []string
}

/**
 * @Author: yang
 * @Description:添加服務(wù)
 * @Date: 2021/4/7 15:36
 */
func (r *RoundRobinBalance) Add (params ...string) error{
    if len(params) == 0 {
        return errors.New("params len 1 at least")
    }
    addr := params[0]
    r.rss = append(r.rss, addr)

    return nil
}

/**
 * @Author: yang
 * @Description:輪詢獲取服務(wù)
 * @Date: 2021/4/7 15:36
 */
func (r *RoundRobinBalance) Next () string {
    if len(r.rss) == 0 {
        return ""
    }
    lens := len(r.rss)
    if r.curIndex >= lens {
        r.curIndex = 0
    }
    curAdd := r.rss[r.curIndex ]
    r.curIndex = (r.curIndex + 1) % lens
    return curAdd
}

5. 測試

簡單調(diào)用下方法看看結(jié)果

/**
 * @Author: yang
 * @Description:測試
 * @Date: 2021/4/7 15:36
 */
func main(){
    rb := new(RoundRobinBalance)
    rb.Add("127.0.0.1:80")
    rb.Add("127.0.0.1:81")
    rb.Add("127.0.0.1:82")
    rb.Add("127.0.0.1:83")

    fmt.Println(rb.Next())
    fmt.Println(rb.Next())
    fmt.Println(rb.Next())
    fmt.Println(rb.Next())
    fmt.Println(rb.Next())
    fmt.Println(rb.Next())
}

go run main.go 

127.0.0.1:80
127.0.0.1:81
127.0.0.1:82
127.0.0.1:83
127.0.0.1:80
127.0.0.1:81

二,Nginx 負(fù)載均衡的加權(quán)輪詢 (weighted-round-robin)

進(jìn)入主題

1. nginx 配置

http {  
    upstream cluster {  
        server 192.168.1.2 weight=5;  
        server 192.168.1.3 weight=3;  
        server 192.168.1.4 weight=1;  
    }  

location / {
       proxy_set_header X-Real-IP $remote_addr;               //返回真實(shí)IP
       proxy_pass http://cluster;                           //代理指向cluster 
   }

2. 加權(quán)算法簡介-特點(diǎn)

不同的服務(wù)器的配置,部署的應(yīng)用數(shù)量,網(wǎng)絡(luò)狀況等都會導(dǎo)致服務(wù)器處理能力會不一樣,所以簡單的 輪詢 算法將不再適用,而引入 了加權(quán)輪詢 算法:根據(jù)服務(wù)器不同的處理能力,給每個(gè)服務(wù)器分配不同的權(quán)值,根據(jù)不同的權(quán)值將不同的服務(wù)器分配到對應(yīng)的服務(wù)器上;

請求數(shù)量較大時(shí),每個(gè)服務(wù)處理請求的數(shù)量之比會趨向于權(quán)重之比。

3. 算法說明

在 Nginx加權(quán)輪詢算法 中,每個(gè)節(jié)點(diǎn)都有3個(gè)權(quán)重的變量

  • Weight : 配置的權(quán)重,根據(jù)配置文件初始化每個(gè)服務(wù)器節(jié)點(diǎn)的權(quán)重
  • currentWeight : 節(jié)點(diǎn)的當(dāng)前權(quán)重,初始化時(shí)是配置的權(quán)重,隨后會一直變更
  • effectiveWeight : 有效的權(quán)重,初始值為 weight ,通訊過程中發(fā)現(xiàn)節(jié)點(diǎn)異常,則 -1 ,之后再次選擇本節(jié)點(diǎn),調(diào)用成功一次則 +1 ,直到恢復(fù)到 weight。這個(gè)參數(shù)可以用于做降權(quán)?;蛘哒f是你的設(shè)置的權(quán)限修正。。

Nginx加權(quán)輪詢算法 的邏輯實(shí)現(xiàn)

  • 輪詢所有節(jié)點(diǎn),計(jì)算當(dāng)前狀態(tài)下所有的節(jié)點(diǎn)的 effectiveWeight 之和 作為 totalWeight;
  • 更新每個(gè)節(jié)點(diǎn)的 currentWeight , currentWeight = currentWeight + effectiveWeight; 選出所有節(jié)點(diǎn) currentWeight 中最大的一個(gè)節(jié)點(diǎn)作為選中節(jié)點(diǎn);
  • 選擇中的節(jié)點(diǎn)再次更新 currentWeight, currentWeight = currentWeight - totalWeight;

4. 簡單舉例

注意:實(shí)現(xiàn)中不考慮健康檢查,即所有的節(jié)點(diǎn)都是100%可用的,所以 effectiveWeight 等于 weight
假設(shè):現(xiàn)在有3個(gè)節(jié)點(diǎn) {A, B, C} 分別權(quán)重為:{4, 2, 1};請求7次

第N次請求 請求前?currentWeight 選中的節(jié)點(diǎn) 請求后?currentWeight
1 [serverA=4, serverB=2, serverC=1] serverA [serverA=1, serverB=4, serverC=2]
2 [serverA=1, serverB=4, serverC=2] serverB [serverA=5, serverB=-1, serverC=3]
3 [serverA=5, serverB=-1, serverC=3] serverA [serverA=2, serverB=1, serverC=4]
4 [serverA=2, serverB=1, serverC=4] serverA [serverA=-1, serverB=3, serverC=5]
5 [serverA=-1, serverB=3, serverC=5] serverC [serverA=3, serverB=5, serverC=-1]
6 [serverA=3, serverB=5, serverC=-1] serverA [serverA=0, serverB=7, serverC=0]
7 [serverA=0, serverB=7, serverC=0] serverB [serverA=4, serverB=2, serverC=1]

totaoWeight = 4 + 2 + 1 = 7
第一次請求: serverA = 4 + 4 = 8 , serverB = 2 + 2 = 4, serverC = 1 + 1 = 2; 最大的是 serverA ; 所以選擇 serverA ;然后serverA = 8 - 7 = 1;最后得出:serverA=1, serverB=4, serverC=2
第二次請求: serverA = 1 + 4 = 5; serverB = 4 + 2 = 6 ; serverC = 2 + 1 = 3;最大的是 serverB ; 所以選擇 serverB ; 然后 serverB = 6 - 7 = -1 ;最后得出: serverA=5, serverB=-1, serverC=3
以此類推。。。

5. 代碼實(shí)現(xiàn)

以golang實(shí)現(xiàn)下上面的邏輯:

type WeightRoundRobinBalance struct {
    curIndex int
    rss []*WeightNode
}

type WeightNode struct {
    weight int // 配置的權(quán)重,即在配置文件或初始化時(shí)約定好的每個(gè)節(jié)點(diǎn)的權(quán)重
    currentWeight int //節(jié)點(diǎn)當(dāng)前權(quán)重,會一直變化
    effectiveWeight int //有效權(quán)重,初始值為weight, 通訊過程中發(fā)現(xiàn)節(jié)點(diǎn)異常,則-1 ,之后再次選取本節(jié)點(diǎn),調(diào)用成功一次則+1,直達(dá)恢復(fù)到weight 。 用于健康檢查,處理異常節(jié)點(diǎn),降低其權(quán)重。
    addr string // 服務(wù)器addr
}

/**
 * @Author: yang
 * @Description:添加服務(wù)
 * @Date: 2021/4/7 15:36
 */
func (r *WeightRoundRobinBalance) Add (params ...string) error{
    if len(params) != 2{
        return errors.New("params len need 2")
    }
    // @Todo 獲取值
    addr := params[0]
    parInt, err  := strconv.ParseInt(params[1], 10, 64)
    if err != nil {
        return err
    }
    node := &WeightNode{
        weight: int(parInt),
        effectiveWeight: int(parInt),  // 初始化時(shí)有效權(quán)重 = 配置權(quán)重值
        currentWeight: int(parInt), // 初始化時(shí)當(dāng)前權(quán)重 = 配置權(quán)重值
        addr: addr,
    }
    r.rss = append(r.rss, node)
    return nil
}

/**
 * @Author: yang
 * @Description:輪詢獲取服務(wù)
 * @Date: 2021/4/7 15:36
 */
func (r *WeightRoundRobinBalance) Next () string {
    // @Todo 沒有服務(wù)
    if len(r.rss) == 0 {
        return ""
    }

    totalWeight := 0
    var maxWeightNode *WeightNode
    for key , node  := range r.rss {
        // @Todo 計(jì)算當(dāng)前狀態(tài)下所有節(jié)點(diǎn)的effectiveWeight之和totalWeight
        totalWeight += node.effectiveWeight

        // @Todo 計(jì)算currentWeight
        node.currentWeight += node.effectiveWeight

        // @Todo 尋找權(quán)重最大的
        if maxWeightNode == nil ||  maxWeightNode.currentWeight < node.currentWeight {
            maxWeightNode = node
            r.curIndex = key
        }
    }

    // @Todo 更新選中節(jié)點(diǎn)的currentWeight
    maxWeightNode.currentWeight -= totalWeight

    // @Todo 返回addr
    return maxWeightNode.addr
}

6. 測試驗(yàn)證

/**
 * @Author: yang
 * @Description:測試
 * @Date: 2021/4/7 15:36
 */
func main(){
    rb := new(WeightRoundRobinBalance)
    rb.Add("127.0.0.1:80", "4")
    rb.Add("127.0.0.1:81", "2")
    rb.Add("127.0.0.1:82", "1")

    fmt.Println(rb.Next())
    fmt.Println(rb.Next())
    fmt.Println(rb.Next())
    fmt.Println(rb.Next())
    fmt.Println(rb.Next())
    fmt.Println(rb.Next())
    fmt.Println(rb.Next())
}

執(zhí)行下看下結(jié)果:

run main.go

127.0.0.1:80
127.0.0.1:81
127.0.0.1:80
127.0.0.1:80
127.0.0.1:82
127.0.0.1:80
127.0.0.1:81

到此這篇關(guān)于Go 實(shí)現(xiàn) Nginx 加權(quán)輪詢算法的方法步驟的文章就介紹到這了,更多相關(guān)Go 實(shí)現(xiàn)Nginx加權(quán)輪詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Go語言中的包Package詳解

    Go語言中的包Package詳解

    本文詳細(xì)講解了Go語言中的包Package,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-07-07
  • Golang?編寫Tcp服務(wù)器的解決方案

    Golang?編寫Tcp服務(wù)器的解決方案

    Golang?作為廣泛用于服務(wù)端和云計(jì)算領(lǐng)域的編程語言,tcp?socket?是其中至關(guān)重要的功能,這篇文章給大家介紹Golang?開發(fā)?Tcp?服務(wù)器及拆包粘包、優(yōu)雅關(guān)閉的解決方案,感興趣的朋友一起看看吧
    2022-10-10
  • Go語言LeetCode題解1046最后一塊石頭的重量

    Go語言LeetCode題解1046最后一塊石頭的重量

    這篇文章主要為大家介紹了Go語言LeetCode題解1046最后一塊石頭的重量,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • GO語言 復(fù)合類型專題

    GO語言 復(fù)合類型專題

    這篇文章主要介紹了GO語言 復(fù)合類型的的相關(guān)資料,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • Go語言中的數(shù)據(jù)競爭模式詳解

    Go語言中的數(shù)據(jù)競爭模式詳解

    這篇文章主要介紹了Go語言中的數(shù)據(jù)競爭模式詳解,主要基于在Uber的Go monorepo中發(fā)現(xiàn)的各種數(shù)據(jù)競爭模式,分析了其背后的原因與分類,需要的朋友可以參考一下
    2022-07-07
  • 基于Go+OpenCV實(shí)現(xiàn)人臉識別功能的詳細(xì)示例

    基于Go+OpenCV實(shí)現(xiàn)人臉識別功能的詳細(xì)示例

    OpenCV是一個(gè)強(qiáng)大的計(jì)算機(jī)視覺庫,提供了豐富的圖像處理和計(jì)算機(jī)視覺算法,本文將向你介紹在Mac上安裝OpenCV的步驟,并演示如何使用Go的OpenCV綁定庫進(jìn)行人臉識別,需要的朋友可以參考下
    2023-07-07
  • go語言中if語句用法實(shí)例

    go語言中if語句用法實(shí)例

    這篇文章主要介紹了go語言中if語句用法,以實(shí)例形式分析了if語句的定義及使用技巧,非常具有實(shí)用價(jià)值,需要的朋友可以參考下
    2015-02-02
  • 使用Go語言編寫HTTP中間件的示例詳解

    使用Go語言編寫HTTP中間件的示例詳解

    在Go語言中,HTTP中間件是一種處理HTTP請求和響應(yīng)的函數(shù),它可以攔截到請求并對其進(jìn)行處理,然后再將請求傳遞給下一個(gè)中間件或目標(biāo)處理程序,本文給大家介紹了使用Go語言編寫HTTP中間件的示例,文中有相關(guān)的代碼示例供大家參考,需要的朋友可以參考下
    2024-01-01
  • Golang泛型實(shí)現(xiàn)類型轉(zhuǎn)換的方法實(shí)例

    Golang泛型實(shí)現(xiàn)類型轉(zhuǎn)換的方法實(shí)例

    將一個(gè)值從一種類型轉(zhuǎn)換到另一種類型,便發(fā)生了類型轉(zhuǎn)換,下面這篇文章主要給大家介紹了關(guān)于Golang泛型實(shí)現(xiàn)類型轉(zhuǎn)換的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-12-12
  • Go語言中的錯誤處理最佳實(shí)踐詳解

    Go語言中的錯誤處理最佳實(shí)踐詳解

    這篇文章主要為大家詳細(xì)介紹了Go語言中的錯誤處理的相關(guān)知識,文中的示例代碼講解詳細(xì),對我們深入了解Go語言有一定的幫助,需要的可以參考下
    2023-08-08

最新評論