使用go來實現一個簡單的負載均衡

How does our simple load balancer work

負載均衡有不同的負載策略

Round Robin:輪詢,就是每個請求依次打到每個服務商去

Weighted Round Robin :加權輪詢,額外加了權重

Least Connections :最少連接,優先請求到連接數最少的服務器上去

補充的其它策略參考 https://blog.csdn.net/qq_28119741/article/details/102333133

我們這次實現的負載均衡,使用三者上面最簡單的一個,輪詢

lb-archi.pnguploading.gif正在上傳…重新上傳取消

輪詢是簡單的,它給了每個後端相等的機會,接受請求或者任務

lb-rr.pnguploading.gif正在上傳…重新上傳取消

如上圖所示,循環接受轉發的請求,任務,但是,我們不能直接用這個不是嗎?

如果一個backend不可用了怎麼辦,我們可能不想再分配給它,所以我們需要只分配給運行正常的backend

Lets define some structs

在改正這個方案後,現在我們知道我們想要一個方法知道一個 backend的全部詳細的信息,我們需要跟蹤這個backend是alive or dead 同時也要保持跟蹤的這個url

所以我們簡單的定義了一個結構體hold我們的後端

type Backend struct {
  URL          *url.URL
  Alive        bool
  mux          sync.RWMutex
  ReverseProxy *httputil.ReverseProxy
}

不要擔心,後面我會解釋這些字段的含義

現在我們需要一個方式跟蹤全部的後端在我們的複製均衡裏面,對於這個我們可以簡單的使用一個slice和一個計數變量。我們定義瞭如下的結構體

type ServerPool struct {
  backends []*Backend
  current  uint64
}

Use of the ReverseProxy

正如我們已經說明的,負載均衡的目標是要把流量分配到不同的後端,然後返回結果給客戶端。

go的文檔是這樣說明reverseproxy的

ReverseProxy is an HTTP Handler that takes an incoming request and sends it to another server, proxying the response back to the client.

反向代理是一個接受一個請求,然後轉發給另一個服務,並代理這個響應返回給客戶端  的一個http handler

反向代理的說明可以參考 https://blog.csdn.net/qq_28119741/article/details/94648300

這正是我們想要的,不需要重複造輪子。我們可以簡單的轉發我們的原始請求通過這個反向代理

u, _ := url.Parse("http://localhost:8080")
rp := httputil.NewSingleHostReverseProxy(u)
  
// initialize your server and add this as handler
http.HandlerFunc(rp.ServeHTTP)

使用 httputil.NewSingleHostReverseProxy(url) 我們初始化了一個反向代理可以轉發請求沿着這個url

在上面的例子中,全部的請求被傳遞到 localhost:8080,同時結果被髮送給客戶端

Selection Process

在下一次的轉發前,我們需要摘掉掛掉的後端,但是做任何事之前我們需要一個計數的方法

下面的代碼用來計算下一個請求輪詢到的後端的索引

func (s *ServerPool) NextIndex() int {
  return int(atomic.AddUint64(&s.current, uint64(1)) % uint64(len(s.backends)))
}

這裏使用原子變量,就不需要鎖來消耗資源了

Picking up an alive backend

這裏我們將要處理掛掉的後端

lb-slice-traverse.pnguploading.gif轉存失敗重新上傳取消

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章