這是第 44 篇不摻水的原創,想獲取更多原創好文,請掃 👆上方二維碼關注咱們吧~
本文首發於政採雲前端團隊博客:五分鐘看懂 Nginx 負載均衡html
對於電商平臺而言,隨着業務的不斷髮展壯大,網站訪問量和數據量也隨之急劇增加,該狀況的產生給服務器帶來了必定的負擔。從用戶體驗層面而言,因爲服務器端數據處理帶來的時延,每每致使頁面的響應速度過慢、操做流暢性受阻等問題。這在某種程度上甚至會潛在影響平臺的成交量。提供高效率,高質量的服務成爲亟待解決的問題。負載均衡策略的出現和發展成爲緩解上述問題的有效途徑。本文將帶你瞭解基於 Nginx 實現的負載均衡。前端
負載均衡(Load Balance),它在網絡現有結構之上能夠提供一種廉價、有效、透明的方法來擴展網絡設備和服務器的帶寬,並能夠在必定程度上增長吞吐量、增強網絡數據處理能力、提升網絡的靈活性和可用性等。用官網的話說,它充當着網絡流中「交通指揮官」的角色,「站在」服務器前處理全部服務器端和客戶端之間的請求,從而最大程度地提升響應速率和容量利用率,同時確保任何服務器都沒有超負荷工做。若是單個服務器出現故障,負載均衡的方法會將流量重定向到其他的集羣服務器,以保證服務的穩定性。當新的服務器添加到服務器組後,也可經過負載均衡的方法使其開始自動處理客戶端發來的請求。(詳情可參考:What Is Load Balancing?)node
簡言之,負載均衡實際上就是將大量請求進行分佈式處理的策略。nginx
經過上文簡單的概念介紹,你可能對負載均衡有了一個初步的瞭解,知道它是一種調度策略。那麼問題來了,Nginx 又是什麼呢?Nginx 如何實現負載均衡?這就要從正向代理和反向代理提及了。git
正向代理github
正向代理(Forward Proxy)最大的特色是,客戶端很是明確要訪問的服務器地址,它代理客戶端,替客戶端發出請求。好比:棵學上網,俗稱 FQ(警告⚠️:FQ 操做違反相關法律規定,本文只是爲了解釋正向代理向讀者舉個例子,僅供學習參考,切勿盲目 FQ)。算法
假設客戶端想要訪問 Google,它明確知道待訪問的服務器地址是 www.google.com/,但因爲條件限制,它找… Google 的」朋友」:代理服務器。客戶端把請求發給代理服務器,由代理服務器代替它請求 Google,最終再將響應返回給客戶端。這即是一次正向代理的過程,該過程當中服務器並不知道真正發出請求的是誰。express
反向代理npm
那麼,隨着請求量的爆發式增加,服務器以爲本身一我的始終是應付不過來,須要兄弟服務器們幫忙,因而它喊來了本身的兄弟以及代理服務器朋友。緩存
此時,來自不一樣客戶端的全部請求實際上都發到了代理服務器處,再由代理服務器按照必定的規則將請求分發給各個服務器。
這就是反向代理(Reverse Proxy),反向代理隱藏了服務器的信息,它代理的是服務器端,代其接收請求。換句話說,反向代理的過程當中,客戶端並不知道具體是哪臺服務器處理了本身的請求。如此一來,既提升了訪問速度,又爲安全性提供了保證。
在這之中,反向代理須要考慮的問題是,如何進行均衡分工,控制流量,避免出現局部節點負載過大的問題。通俗的講,就是如何爲每臺服務器合理的分配請求,使其總體具備更高的工做效率和資源利用率。
Nginx 是什麼?
Nginx 做爲一個基於 C 實現的高性能 Web 服務器,能夠經過系列算法解決上述的負載均衡問題。而且因爲它具備高併發、高可靠性、高擴展性、開源等特色,成爲開發人員經常使用的反向代理工具。
1. 輪詢 (round-robin)
輪詢爲負載均衡中較爲基礎也較爲簡單的算法,它不須要配置額外參數。假設配置文件中共有 M 臺服務器,該算法遍歷服務器節點列表,並按節點次序每輪選擇一臺服務器處理請求。當全部節點均被調用過一次後,該算法將從第一個節點開始從新一輪遍歷。
特色:因爲該算法中每一個請求按時間順序逐一分配到不一樣的服務器處理,所以適用於服務器性能相近的集羣狀況,其中每一個服務器承載相同的負載。但對於服務器性能不一樣的集羣而言,該算法容易引起資源分配不合理等問題。
二、加權輪詢
爲了不普通輪詢帶來的弊端,加權輪詢應運而生。在加權輪詢中,每一個服務器會有各自的 weight
。通常狀況下,weight
的值越大意味着該服務器的性能越好,能夠承載更多的請求。該算法中,客戶端的請求按權值比例分配,當一個請求到達時,優先爲其分配權值最大的服務器。
特色:加權輪詢能夠應用於服務器性能不等的集羣中,使資源分配更加合理化。
Nginx 加權輪詢源碼可見:ngx_http_upstream_round_robin.c,源碼分析可參考:關於輪詢策略原理的自我理解。其核心思想是,遍歷各服務器節點,並計算節點權值,計算規則爲 current_weight
與其對應的 effective_weight
之和,每輪遍歷中選出權值最大的節點做爲最優服務器節點。其中 effective_weight
會在算法的執行過程當中隨資源狀況和響應狀況而改變。較爲核心的部分以下:
for (peer = rrp->peers->peer, i = 0; peer; /* peer 爲當前遍歷的服務器結點*/ peer = peer->next, i++) { ... /* 每輪遍歷會更新 peer 當前的權值*/ peer->current_weight += peer->effective_weight; ... /* best 爲當前服務器中的最優節點,即本輪中選中的服務器節點*/ if (best == NULL || peer->current_weight > best->current_weight) { best = peer; p = i; } ... } 複製代碼
3. IP 哈希(IP hash)
ip_hash
依據發出請求的客戶端 IP 的 hash 值來分配服務器,該算法能夠保證同 IP 發出的請求映射到同一服務器,或者具備相同 hash 值的不一樣 IP 映射到同一服務器。
特色:該算法在必定程度上解決了集羣部署環境下 Session 不共享的問題。
Session 不共享問題是說,假設用戶已經登陸過,此時發出的請求被分配到了 A 服務器,但 A 服務器忽然宕機,用戶的請求則會被轉發到 B 服務器。但因爲 Session 不共享,B 沒法直接讀取用戶的登陸信息來繼續執行其餘操做。
實際應用中,咱們能夠利用 ip_hash
,將一部分 IP 下的請求轉發到運行新版本服務的服務器,另外一部分轉發到舊版本服務器上,實現灰度發佈。再者,如遇到文件過大致使請求超時的狀況,也能夠利用 ip_hash
進行文件的分片上傳,它能夠保證同客戶端發出的文件切片轉發到同一服務器,利於其接收切片以及後續的文件合併操做。
四、其餘算法
URL hash
url_hash
是根據請求的 URL 的 hash 值來分配服務器。該算法的特色是,相同 URL 的請求會分配給固定的服務器,當存在緩存的時候,效率通常較高。然而 Nginx 默認不支持這種負載均衡算法,須要依賴第三方庫。
最小鏈接數(Least Connections)
假設共有 臺服務器,當有新的請求出現時,遍歷服務器節點列表並選取其中鏈接數最小的一臺服務器來響應當前請求。鏈接數能夠理解爲當前處理的請求數。
說了這麼多理論,究竟基於 Nginx 的負載均衡要怎麼用呢?接下來,將以加權輪詢算法爲例,帶你們嘗試經過本身的一臺筆記本 + Nginx + Node 測試一下負載均衡。因爲沒有多臺服務器,因而經過本身筆記本的多個不一樣端口來模擬不一樣的服務器。
Step 1:確保本身的電腦中,Nginx 已安裝並可以成功啓動(以 Mac 爲例)
若是你也遇到了像我同樣因爲端口占用致使 Nginx 啓動失敗的問題,能夠嘗試下述步驟修改配置文件中的端口號
相關文件路徑
修改 nginx.conf 文件中的端口
server {
# listen 8080;
listen 8086;
server_name localhost;
}
複製代碼
Nginx 配置文件 nginx.conf 中主要包含如下幾個部分:
暫停 Nginx 並重啓
// 暫停 Nginx 服務 sudo nginx -s stop // 啓動 Nginx 服務 nginx 複製代碼
打開 http://localhost:8086/ 測試是否成功,若是顯示下圖,則證實啓動成功~
Step 2:基於 Node + Express 框架來搭建簡單的服務器
Express 是一個簡潔而靈活的輕量級 node.js Web 應用框架(詳情可瞭解 Express),若是第一次使用,請先安裝。
安裝 Express
npm i express
複製代碼
新建 index.js 文件,並寫入代碼
const express = require('express'); const app = express(); // 定義要監聽的端口號 const listenedPort = '8087'; app.get('/', (req, res) => res.send(`Hello World! I am port ${listenedPort}~`)); // 監聽端口 app.listen(listenedPort, () => console.log(`success: ${listenedPort}`)); 複製代碼
啓動服務器
node index.js
複製代碼
此處能夠多起幾個服務,分別讓 Node 監聽 8087,8088,8089 端口,每一個服務中經過 send
不一樣的文案用以區分不一樣的 Server。
Step 3:在 nginx.conf 文件中配置好須要輪詢的服務器和代理
upstream testServer { server localhost:8087 weight=10; server localhost:8088 weight=2; server localhost:8089; } 複製代碼
location / { root html; index index.html index.htm; proxy_pass http://testServer; // testServer 爲本身定義的服務器集羣 } 複製代碼
Step 4:查看結果
重啓 Nginx 服務
經過屢次刷新能夠發現,因爲設置了不一樣的 weight
,端口號爲 8087 的服務器出現的次數最多,同時證明了權值越高,服務器處理請求概率越大的規則。
Nginx 做爲一款優秀的反向代理服務器,能夠經過不一樣的負載均衡算法來解決請求量過大狀況下的服務器資源分配問題。較爲常見的負載均衡算法有輪詢、加權輪詢、IP 哈希等等,可分別應對不一樣的請求場景。若是有興趣能夠去 Github 理解下大神的源碼,有問題也歡迎一塊兒來探討~
政採雲前端團隊(ZooTeam),一個年輕富有激情和創造力的前端團隊,隸屬於政採雲產品研發部,Base 在風景如畫的杭州。團隊現有 50 餘個前端小夥伴,平均年齡 27 歲,近 3 成是全棧工程師,妥妥的青年風暴團。成員構成既有來自於阿里、網易的「老」兵,也有浙大、中科大、杭電等校的應屆新人。團隊在平常的業務對接以外,還在物料體系、工程平臺、搭建平臺、性能體驗、雲端應用、數據分析及可視化等方向進行技術探索和實戰,推進並落地了一系列的內部技術產品,持續探索前端技術體系的新邊界。
若是你想改變一直被事折騰,但願開始能折騰事;若是你想改變一直被告誡須要多些想法,卻無從破局;若是你想改變你有能力去作成那個結果,卻不須要你;若是你想改變你想作成的事須要一個團隊去支撐,但沒你帶人的位置;若是你想改變既定的節奏,將會是「 5 年工做時間 3 年工做經驗」;若是你想改變原本悟性不錯,但老是有那一層窗戶紙的模糊… 若是你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的本身。若是你但願參與到隨着業務騰飛的過程,親手推進一個有着深刻的業務理解、完善的技術體系、技術創造價值、影響力外溢的前端團隊的成長曆程,我以爲咱們該聊聊。任什麼時候間,等着你寫點什麼,發給 ZooTeam@cai-inc.com