你是小阿巴,剛剛開發上線了自己的第一個網站。
前幾天只有幾個人訪問,網站運行得穩穩當當。
你得意地想:做網站也太簡單了吧!

結果一週後,某知名博主 “魚蛋” 不小心推廣了

你急得滿頭大汗,趕緊向號稱 “後端之狗” 的魚皮求救。
你:魚皮 gie gie 救命啊!
魚皮瞭解情況後,淡定地説:加服務器。

你恍然大悟:對哦,我買 3 台服務器,就有 3 個不同的 IP 地址了。只要讓用户自己選擇訪問哪一台,就能分攤流量壓力啦!

魚皮笑了:但如果用户並不知道這些 IP 地址呢?

你撓了撓頭:對啊,這可咋辦!
魚皮:這就要請出我的朋友 LB 了。
你一臉疑惑:LB 是啥?老闆?鏈表?老鴇?

⭐️ 推薦觀看視頻版,有動畫更容易理解:https://bilibili.com/video/BV1e92eBTEkL
第一階段:認識負載均衡
魚皮:LB 是指 負載均衡(Load Balancer),它就像一個 “交通指揮中心”。車輛來了,不是自己隨便選道路,而是由指揮中心統一調度走哪條路線,避免某條路堵死、其他路卻空着。

對於你的問題,你需要一台 反向代理服務器(負載均衡器),對外提供唯一的訪問入口,統一接收所有用户的請求;再根據一定的規則,把請求分配給後端的多台服務器來實際處理,這樣每台服務器的壓力就小很多了。

你眼前一亮:原來如此,通過負載均衡,用户只需要訪問同一個域名,完全不用關心我的網站背後有幾台服務器,我可以使勁加服務器來提高網站的併發量。

魚皮:不錯,而且負載均衡器會實時監測後端服務器的健康狀態。如果發現某台服務器掛了,就不再把流量分給它,自動切換到其他健康的服務器,保證用户訪問不受影響。

此外,負載均衡器在實際使用中,還常常承擔一些額外的職責。比如 SSL 卸載,讓負載均衡器統一處理 HTTPS 的加密解密,後端服務器就不用每台都配置證書了,省事兒又減壓。

第二階段:怎麼實現負載均衡?
你很是激動:哇,聽起來很厲害啊!那我用什麼來做負載均衡呢?
魚皮:像 Nginx、HAProxy 等高性能網關軟件都支持負載均衡功能。比如使用 Nginx,只需要寫下這樣一段配置:
upstream backend {
server 192.168.1.10;
server 192.168.1.11;
server 192.168.1.12;
}
location / {
proxy_pass http://backend;
}
由 3 台服務器組成了一個集羣,Nginx 會自動把收到的請求分配給它們。

你開心了:這麼簡單,爽爽爽!我這就去實現~
於是你成功配置好了 Nginx 負載均衡,這下網站不崩了,用户訪問也更順暢了。
你得意地想:負載均衡不過如此,傻子都能學會哈哈哈哈哈哈!

第三階段:負載均衡也扛不住了咋辦?
一個月後,你的網站又不小心被一個更知名的博主 “驢皮” 分享了,瞬時用户量暴增到幾十萬,竟然把你部署 Nginx 的服務器都給衝爆了!

你慌了:嗚啊,這破 Nginx 接不住這破天的富貴,怎麼辦啊!
難道再加一個 Nginx 來給 Nginx 做負載均衡?但這不是套娃嗎?照樣扛不住啊!

魚皮:別慌!負載均衡不是隻有一種,根據網絡層次可以分很多類。

剛才你用的 Nginx,其實是 七層負載均衡。它工作在應用層,可以根據 HTTP 請求的內容(比如 URL 路徑、Cookie、請求頭等)進行轉發。

它的優點是最靈活、成本最低,大多數中小型網站用它就夠了;但是一般單機只能支撐幾萬到十幾萬併發。
如果想更進一步增加併發,可以用 四層負載均衡。它工作在傳輸層,只根據 IP 地址和端口號進行轉發,不關心 HTTP 請求的具體內容。

正因如此,它的性能很高,能支撐幾十萬甚至上百萬併發。
常用的實現方案是 LVS (Linux Virtual Server,Linux 虛擬服務器),它通過修改網絡數據包的地址信息(IP 或 MAC),把請求轉發到不同的服務器,速度極快。適用於某寶、某東這種級別的大型網站。

你:那有沒有更厲害的?我擔心自己的網站一不小心成為國民級應用。
魚皮:當然!還有二層和三層負載均衡。或者利用專業的硬件設備做負載均衡,比如性能極高的 F5,但價格也極高,入門級的設備都要十幾萬。

你大為震驚:哎呀,這我可買不起了呀……
魚皮:快醒醒吧,這種硬件負載均衡主要用於金融、電信等大型企業,咱們一般用不到。
你突然想到:對了,我聽説有些大公司會用 DNS 來做負載均衡,這算是哪一層呢?
魚皮:問得好,DNS 負載均衡 比較特殊。它嚴格來説屬於應用層,但工作原理和前面講的都不太一樣。
傳統負載均衡是用户請求已經到達服務器後再分配,而 DNS 負載均衡是在用户瀏覽器查詢域名對應的 IP 地址時,DNS 服務器就根據策略(如地域、負載)返回不同的服務器 IP,從而實現流量分配。

它的優點是實現簡單、成本低,適合做全球流量分配,比如國內用户訪問國內服務器,海外用户訪問海外服務器。
缺點是不夠靈活,而且 DNS 有緩存,改了配置不能立即生效。

第四階段:負載均衡算法
你點點頭:那我還是老老實實用七層和四層負載均衡吧。對了,負載均衡器怎麼知道把請求分給哪台服務器呢?
魚皮:這就要靠 負載均衡算法 了,算法分兩大類 —— 靜態算法和動態算法。
靜態算法就是按照固定的規則分配。
1)首先是最簡單的輪詢算法(Round Robin)。就像發撲克牌一樣,一張一張輪着來(第一個請求給服務器 A,第二個給服務器 B,第三個給服務器 C,然後又回到服務器 A),發完一輪再來一輪。

看起來很公平,但如果服務器性能不一樣,有的很閒、有的很忙,怎麼辦?
2)加權輪詢(Weighted Round Robin) 就能解決這個問題,你可以給性能高的服務器設置更高的權重,讓它處理更多請求。

你:等等,如果用户第一次請求分配到服務器 A 並保存了登錄態,第二次請求分配到服務器 B,登錄態不就丟失了麼?

魚皮:沒錯,能想到這點的你非常棒!
3)我們可以用 IP 哈希(Hash)算法來解決這個問題。根據用户的 IP 地址計算一個哈希值,然後分配到對應的服務器。這樣同一個用户的請求總是會分配到同一台服務器,登錄態就不會丟了。

不過 IP Hash 也有缺點,如果很多用户來自同一個大局域網,可能會導致流量分配不均哦,所以現在主流還是用 Redis 做共享 Session。這也是面試時的一個考點(Session 一致性問題的解決方案)。

魚皮:動態算法更靈活,會根據服務器的實時狀態來分配請求。
1)最少連接(Least Connections):哪台服務器當前連接數最少、最閒,就優先把請求分給誰。

2)最快響應(Least Response Time):哪台服務器的響應速度最快、幹活最麻利,就優先把請求分給誰。

小阿巴:這麼多算法,記不住啊!哪個最常用啊?
魚皮笑道:算法千千萬,輪詢佔一半。實際工作中,大部分場景用輪詢或加權輪詢就夠了。
第五階段:其他重要知識點
你:那負載均衡器怎麼知道後端服務器是否健康呢?
魚皮:這就是 健康檢查 機制。負載均衡器會定期(比如每隔幾秒)向後端服務器發送心跳請求,檢查服務器是否正常響應。

如果連續多次失敗,就認為這台服務器掛了,自動把它從服務器列表中剔除。等服務器恢復後,再自動添加回來。

你:哇,就像醫院裏的護士定時查房一樣,太貼心了吧!
等等,負載均衡器能監測後端服務器、替它們分攤壓力,但是萬一負載均衡器自己掛了怎麼辦?
魚皮:問得好,這就是負載均衡的 高可用 問題。
解決辦法是部署多個負載均衡器,採用主從模式。主負載均衡器正常工作,從負載均衡器隨時待命。它們之間會互相發送心跳包,並共享一個虛擬 IP 地址(VIP)。

一旦從節點發現主節點沒有迴應了,就接管這個虛擬 IP,用户訪問的還是同一個 IP 地址,所以毫無感知。

結尾
你感慨道:哇,原來負載均衡有這麼多學問!作用、分類、算法,學到了學到了~
那…… 我現在算是負載均衡專家了吧?!
魚皮從褲兜裏掏出兩個硬幣砸到你的頭上:想啥呢?!你現在只是瞭解了負載均衡的思想,但是實際開發中還有很多玩法。對了,我之前在

你虛心地點點頭:好的,狗魚皮!
