引言
你說妹子太多了,壓力有點大,身體有點吃不消,有點支持不住了。
因而乎,你找了幾個兄弟說:哥們,幫忙分擔一下壓力唄。因而你開始把這些妹子推向你兄弟的魔爪,把妹子一個個的介紹給你不一樣的兄弟,而且盡力撮合他們。PS: 固然本身得留點。算法
這大概就是負載均衡,你既充當着負載均衡器, 也充當着服務器, 你的兄弟就是個服務器。你的壓力相比之下減小了不少,這就是負載均衡的做用。json
用專業術語來講:後端
- 負載均衡創建在現有網絡結構之上,它提供了一種廉價有效透明的方法擴展網絡設備和服務器的帶寬、增長吞吐量、增強網絡數據處理能力、提升網絡的靈活性和可用性。
- 負載均衡(Load Balance)其意思就是分攤到多個操做單元上進行執行,例如Web服務器、FTP服務器、企業關鍵應用服務器和其它關鍵任務服務器等,從而共同完成工做任務。
簡單點來講:服務器
- 其實就是請求太多,一臺服務器處理不過來,把它分攤到多臺服務器處理。
那麼如何將請求分攤到多臺服務器?網絡
接下來一一介紹常見的幾種負載均衡算法。負載均衡
輪詢法
- 將請求按順序輪流地分配到後端服務器上,它均衡地對待後端的每一臺服務器,而不關心服務器實際的鏈接數和當前的系統負載。
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-eAolzy2P-1619539822631)(https://www.classmatelin.top/images/20210427234214.png)]dom
-
Go語言實現示例以下:函數
/** * Author: ClassmateLin * Site: https://www.classmatelin.top * mail: classmatelin.site@gmail.com * Date: 2021/4/26 21:32 */ package main import ( "fmt" ) type RoundRobin struct { servers []string current int } /** 獲取下一個服務器 */ func (R *RoundRobin) next() string { R.current++ R.current = R.current % len(R.servers) // 訪問到最後一個服務器以後,重置會第一臺。 5%5=0。 return R.servers[R.current] } func main() { r := &RoundRobin{ servers: []string{ "192.168.10", "192.168.11", "192.168.12"}, current: -1, } for i := 0; i < 10; i++ { fmt.Printf("| %d | %s |\n", i + 1, r.next()) } }
加權輪詢法
-
每臺後端服務器的配置可能不太同樣,有些性能好,能處理的請求多, 有些則性能比較差,能處理的請求較少。性能
-
它們的抗壓能力不相同,所以按順序的分配服務器的話致使性能好的服務器沒法發揮最大做用,性能差的服務器壓力太大。spa
-
那麼加權輪詢法能夠解決這個問題,給性能好的服務器分配較高的權重,性能差的服務器分配較低的權重。
-
go語言實現的平滑的加權輪詢法:
/** * @Author: ClassmateLin * @Site: https://www.classmatelin.top * @Email: classmatelin.site@gmail.com * @Date: 2021/4/27 22:44 */ package main import "fmt" type Server struct { host string // 主機地址 weight int // 配置的權重 currentWeight int // 當前權重 } func getSever(servers []*Server) (s *Server) { allWeight := 0 // 總權重 for _, server := range servers { if server == nil { return nil } // 每一輪選擇都用自身的權重加到當前權重 allWeight += server.weight server.currentWeight += server.weight // 當前未選中節點或當前節點比以前選中的節點權重高,那麼更新當前選中的節點 if s == nil || server.currentWeight > s.currentWeight{ s = server } } s.currentWeight -= allWeight return } func main() { servers := []*Server{ { "192.168.10.10", 5, 0}, { "192.168.10.11", 2, 0}, { "192.168.10.12", 1, 0}, } for i := 0; i < 20; i++ { server := getSever(servers) if server == nil { continue } fmt.Printf("| %s | %d |\n", server.host, server.weight) } }
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-eVhLqR1j-1619539822633)(https://www.classmatelin.top/images/20210427233715.png)]
- 平滑是指什麼?例若有如下三臺服務器:
A: { host:"192.168.10.10", "weight": 3} B: { host:"192.168.10.11", "weight": 1} C: { host:"192.168.10.12", "weight": 1}
若是出現的序列爲AAABC, 可能會給第一臺機器形成壓力過大。若是出現的序列爲ABACA,避免同時形成同一臺服務器壓力過大的問題,就是平滑的。)
隨機法
-
隨機法就是經過隨機算法,從服務器列表中隨機地選取一臺服務器進行訪問。隨着客戶端調用服務器的次數增長到必定數量級別,每臺服務器的平均訪問次數跟輪詢法的次數相近,也就是說趨近於輪詢法。
-
go實現示例:
/** * @Author: ClassmateLin * @Site: https://www.classmatelin.top * @Email: classmatelin.site@gmail.com * @Date: 2021/4/27 22:44 */ package main import ( "fmt" "math/rand" ) type Random struct { servers []string } func (R *Random) next() string { return R.servers[rand.Intn(len(R.servers))] } func main() { r := Random{ servers: []string{ "192.168.10.10", "192.168.10.11", "192.168.10.12"}, } for i := 0; i < 10; i++ { fmt.Println(r.next()) } }
加權隨機法
-
加權隨機法根據後端機器的配置,系統的負載分配不一樣的權重,按照權重進行隨機選取,與加權輪詢法類似。
-
go語言實現示例:
源地址哈希法
-
源地址哈希法是根據請求來源的地址,經過哈希函數計算獲得的一個數值,用該數值對服務器列表的大小進行取模運算,獲得的結果即是客服端要訪問服務器的序號。
-
採用源地址哈希法進行負載均衡,同一源地址的請求,當服務器列表不變時,它每次都會映射到同一臺服務器進行訪問。
-
go語言實現示例:
最小數鏈接法
-
最小鏈接數法是根據服務器當前的鏈接狀況進行負載均衡的,當請求到來時,會選取當前鏈接數最少的一臺服務器來處理請求。
-
由此也能夠延伸出,根據服務器CPU 佔用最少,根據單位時間內處理請求的效率高低等進行服務器選擇。
-
go語言實現示例: