How does our simple load balancer work
負載均衡有不同的負載策略
Round Robin:輪詢,就是每個請求依次打到每個服務商去
Weighted Round Robin :加權輪詢,額外加了權重
Least Connections :最少連接,優先請求到連接數最少的服務器上去
補充的其它策略參考 https://blog.csdn.net/qq_28119741/article/details/102333133
我們這次實現的負載均衡,使用三者上面最簡單的一個,輪詢
輪詢是簡單的,它給了每個後端相等的機會,接受請求或者任務
如上圖所示,循環接受轉發的請求,任務,但是,我們不能直接用這個不是嗎?
如果一個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
這裏我們將要處理掛掉的後端