概述
????????在現代 Web 架構中,Nginx 作為高并發、高性能的 HTTP 和反向代理服務器,被廣泛應用于提升服務性能、增強系統安全性和實現負載均衡。其中,反向代理能夠隱藏后端服務器信息并優化請求處理流程,負載均衡則可將請求分發到多個后端節點,大幅提升系統并發能力。
一、反向代理(proxy 模塊)
1. 作用
- 性能優化:增加業務并發量。Nginx 可緩存靜態資源,減少后端服務器處理壓力,提升響應速度;同時通過連接復用,提高并發處理能力。
- 提高業務安全性:隱藏后端業務服務器的真實 IP 和端口信息,避免直接暴露在公網中,降低被攻擊風險,
- 功能擴展:可實現請求過濾、URL 重寫、SSL 終結等功能,簡化后端服務器的配置復雜度。
2. 核心配置語法
反向代理的核心是通過location 塊配合proxy_pass?指令,將特定請求轉發至后端服務器。
location URI {proxy_pass 后端服務器地址;
}
URI:匹配路徑:指定需要代理的客戶端請求路徑(如/mp3、/download);
proxy_pass 后端服務器地址;?指定請求轉發的后端服務器地址(可包含 IP、端口及路徑)
- 后端服務器地址:實際訪問地址
明確目標:代理服務器正確轉發 + 后端服務器正確響應
(1)路徑拼接規則
????????Nginx 會自動將location中的匹配路徑與proxy_pass的后端地址拼接,拼接方式取決于后端地址是否以斜杠結尾:
- 若后端地址無斜杠(如http://192.168.140.11/music),客戶端請求路徑會直接拼接在后端路徑后;
- 若后端地址有斜杠(如http://192.168.140.11/music/),客戶端請求路徑會替換location的匹配路徑后拼接。
location /test1 {
? ? ? ? proxy_pass http://aa.linux.com;? ?//nginx的反向代理,hosts文件需要加上dns解析
}
192.168.140.10/music? ? //?192.168.140.10的網頁目錄(/var/www/html)下的music文件
192.168.140.10:8088/music? ?//若nginx換端口? ?
(2)不同場景下的配置示例
場景 1:帶 URI 的精確匹配轉發
當訪問 Nginx 的任意路徑時,代理到后端服務器的/music3 路徑:
location / {proxy_pass http://192.168.140.20/music3;
}
# 說明:當客戶端訪問 Nginx 服務器的任意路徑(例如http://你的Nginx地址/xxx)時,
# Nginx 會將該請求轉發到 http://192.168.140.20/music3 對應的服務,
# 并將后端服務的響應返回給客戶端。
場景 2:不帶 URI 的路徑轉發
當后端服務器沒有特定 URI 時,Nginx 會將?location?中的 URI 拼接到后端地址:
location /test {proxy_pass http://192.168.140.10;
}
# 說明:此時請求http://nginx-ip/test/xyz會被轉發為http://192.168.140.10:9000/test/xyz
場景 3:正則表達式匹配的特殊規則
當 location 使用正則表達式(~
或~*
)匹配請求時,proxy_pass后的后端地址不允許包含任何 URI,否則會報錯:
# 正確配置(無URI)
location ~ /music {proxy_pass http://192.168.140.10;
}# 錯誤配置(包含URI,會導致Nginx啟動失敗)
# location ~ /music {
# proxy_pass http://192.168.140.10/project; # 此處錯誤
# }
3. 后端服務器記錄客戶端真實 IP
默認情況下,后端服務器會將 Nginx 的 IP 識別為客戶端 IP,如需記錄真實客戶端 IP,需通過以下配置實現:
(1)Nginx 反向代理添加標識字段
在代理規則中添加X-REAL-IP
或X-Forwarded-For
字段,傳遞客戶端真實 IP:
location /mp3 {proxy_pass http://192.168.140.11/music;# 傳遞客戶端真實IP給后端proxy_set_header X-REAL-IP $remote_addr;# 若后端為多代理架構,使用X-Forwarded-For記錄代理鏈proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
(2)
① 后端為 Apache(httpd)時的配置
修改 Apache 的日志格式,使其解析X-REAL-IP
字段:
# 在httpd.conf中修改combined日志格式
LogFormat "%{X-REAL-IP}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
② 后端為 Nginx 時的配置
修改后端 Nginx 的日志格式,使用$http_x_forwarded_for
獲取真實 IP:
# 在后端Nginx的main日志格式中添加
log_format main '$http_x_forwarded_for [$time_local] "$request" ''$status $body_bytes_sent "$http_referer" ''"$http_user_agent"';
二、負載均衡(upstream 模塊)
????????Nginx 的?upstream 模塊是用于管理后端服務器集群的核心組件,通過它可以實現對多臺后端服務器的統一調度、狀態監控和故障處理。
1、 作用
- 提升并發能力:將客戶端請求分發到多個后端服務器,避免單節點壓力過大,提高系統整體吞吐量。
- 增強可用性:通過健康檢查自動剔除故障節點,確保服務持續可用;同時支持備用節點,進一步提升可靠性。
- 靈活擴展:可根據業務需求動態增減后端節點,實現無縫擴容。
2、工作流程
(以 Nginx 為負載均衡器為例)
- 定義后端服務器組:通過upstream塊定義一組后端服務器(如192.168.1.10:8080、192.168.1.11:8080),并配置調度算法和節點參數。
- 接收客戶端請求:客戶端請求首先到達 Nginx 負載均衡器(通常是前端入口服務器)。
- 選擇后端節點:Nginx 根據upstream中配置的調度算法(如輪詢、IP 哈希等),從服務器組中選擇一臺 “合適” 的后端服務器。
- 轉發請求并返回響應:Nginx 將客戶端請求轉發到選中的后端服務器,后端處理后將響應返回給 Nginx,再由 Nginx 返回給客戶端。
3、 調度算法 / 策略
Nginx 提供多種負載均衡算法,可根據業務場景選擇:
① rr(Round Robin,輪詢)
upstream app_servers {server 192.168.140.10:9000 weight=3; # 權重3,接收3/5的請求server 192.168.140.11:9000 weight=2; # 權重2,接收2/5的請求
}
- 默認算法,請求按順序輪流分配到后端節點。
- 支持通過 weight 設置權重(權重越高,分配的請求越多),適用于后端節點性能不均的場景。
- 會話持久問題(見補充)
② sh(Source Hash,源哈希)
upstream app_servers {ip_hash; # 啟用源哈希算法server 192.168.140.10:9000;server 192.168.140.11:9000;
}
- 根據客戶端 IP 計算哈希值,將同一客戶端的請求固定分配到同一后端節點。
- 適用于需要會話保持的場景(如未使用分布式會話的系統)。
③ lc(Least Connections,最少連接)
upstream app_servers {least_conn; # 啟用最少連接算法server 192.168.140.10:9000;server 192.168.140.11:9000;
}
- 優先將請求分配到當前連接數最少的后端節點,適用于請求處理時間差異較大的場景。
4、健康狀態檢查與故障隔離
自動檢測后端服務器的可用性,對故障節點進行隔離,避免請求轉發到不可用的服務器,保障服務穩定性。
5、配置語法與示例
# 定義后端服務器組
upstream 服務器組名稱 {[調度算法]; # 可選,默認rrserver IP:port [參數]; # 后端節點及可選參數server IP:port [參數];
}# 引用服務器組
location URI {proxy_pass http://服務器組名稱;
}
常用參數說明
- weight=數值:設置節點權重(默認 1),數值越大優先級越高。
- max_fails=次數:允許請求失敗的最大次數(默認 1),超過則標記節點為不可用。
- fail_timeout=秒數:標記節點不可用的時間(默認 10 秒),超時后會重新檢測節點。
- backup:標記為備用節點,僅當所有非備用節點不可用時才接收請求。
- down:標記節點為永久不可用(手動下線時使用)。
完整配置示例
# 定義Java應用服務器組(使用輪詢算法)
upstream java_servers {server 192.168.140.10:9000 weight=1 max_fails=2 fail_timeout=3s; # 權重1,失敗2次后3秒內不分配server 192.168.140.10:9001 weight=1 max_fails=2 fail_timeout=3s;server 127.0.0.1:8000 backup; # 備用節點,主節點全故障時啟用
}# 轉發所有根路徑請求到java_servers
location / {proxy_pass http://java_servers/project/;proxy_set_header X-REAL-IP $remote_addr; # 傳遞真實客戶端IPproxy_set_header Host $host; # 傳遞原始請求的Host頭
}# 轉發/music路徑請求到java_servers的/music目錄
location /mp3 {proxy_pass http://java_servers/music/;proxy_set_header X-REAL-IP $remote_addr;
}# 備用節點的本地服務配置(當主節點故障時提供降級頁面)
server {listen 8000;server_name localhost;location / {root /usr/share/nginx/sorry; # 存放降級頁面的目錄index index.html; # 降級頁面}
}
演示:
環境準備
假設有 3 臺機器,IP 分別為:
負載均衡器(Nginx):
192.168.140.20
(接收客戶端請求,分發到后端)后端服務器 1(nginx):
192.168.140.10
后端服務器 2(httpd):
192.168.140.30
步驟 1:配置后端服務器(10?和 30)
在 10 和 30 上安裝 Nginx/httpd(模擬 Web 服務)
創建測試頁面(區分兩臺服務器,方便驗證負載均衡效果)
- echo "This is backend server 10 " ?> /usr/local/nginx/html/index.html?? ? //在 10?上執行
- echo "This is backend server 30" > /usr/share/nginx/html/index.html? ?? //在 30?上執行
驗證后端服務:
????????分別訪問 http://192.168.140.10 和 http://192.168.140.30,?應顯示各自的測試內容。
步驟 2:配置負載均衡器(100)
????????在負載均衡器上安裝 Nginx,并通過 upstream 模塊定義后端服務器集群,實現請求分發。
安裝 Nginx:
????????修改 Nginx 配置文件(/usr/local/nginx/conf/nginx.conf),在http塊中添加 upstream(后端集群)和server(負載均衡規則):
http {# ... 其他默認配置(保留不動)# 1. 定義后端服務器集群(包含101和102)upstream backend_servers {# 調度算法:默認輪詢(可按需改為weight、ip_hash等)server 192.168.1.101:80; # 后端服務器1server 192.168.1.102:80; # 后端服務器2server 127.0.0.1:8000 backup; # 備用節點,主節點全故障時啟用# 可選:添加健康檢查參數(自動剔除故障節點)# max_fails=2:允許2次請求失敗# fail_timeout=10s:失敗后隔離10秒# server 192.168.1.101:80 max_fails=2 fail_timeout=10s;}# 2. 配置負載均衡入口(接收客戶端請求)server {listen 80; # 監聽80端口(客戶端訪問的端口)server_name 192.168.1.100; # 負載均衡器的IP# 所有請求轉發到后端集群location / {proxy_pass http://backend_servers; # 轉發到upstream定義的集群proxy_set_header Host $host; # 傳遞客戶端訪問的Host(如192.168.1.100)proxy_set_header X-Real-IP $remote_addr;proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;proxy_set_header X-Forwarded-Proto $scheme; # 傳遞協議(http/https)}}server {listen 8000; # 備用服務端口server_name 127.0.0.1;location / {root /usr/local/nginx/backup_html; # 備用服務的網頁目錄index index.html;}}
}
# 創建備用服務的測試頁面:
mkdir -p /usr/local/nginx/backup_html
# 寫入備用內容(如“主節點故障,已切換至備用服務”)
echo "This is backup server (local 8000)" > /usr/local/nginx/backup_html/index.html
//?加權輪詢:若后端服務器性能不同,可通過weight分配請求比例(值越高,接收請求越多):
upstream backend_servers {server 192.168.1.101:80 weight=3; # 承擔3/5的請求server 192.168.1.102:80 weight=2; # 承擔2/5的請求
}
// 若需同一客戶端請求固定到同一后端(如未做會話共享),使用ip_hash:
upstream backend_servers {ip_hash; # 基于客戶端IP哈希server 192.168.1.101:80;server 192.168.1.102:80;
}
檢查配置并重啟 Nginx
步驟 3:修改httpd/nginx配置文件
- vim /etc/httpd/conf/httpd.conf?
- vim /usr/local/nginx/conf/nginx.conf
步驟 4:測試負載均衡效果
通過客戶端訪問負載均衡器的 IP(192.168.140.20),驗證請求是否被分發到兩臺后端服務器。
1、多次訪問測試:
在瀏覽器或終端多次訪問?http://192.168.140.20,應交替顯示:
This is backend server 10
This is backend server 30
(默認輪詢算法下,請求會依次分發到 10 和 30)。
2、模擬故障測試:
- 停止后端10 的 Nginx(systemctl stop nginx),再次訪問?http://192.168.140.20,應始終顯示 30 的內容(Nginx 會自動剔除故障節點)。
- 停止后端10 和20的,再次訪問?http://192.168.140.20,應始終顯示備用節點
特殊的:如果負載均衡如此設置
- echo "This is backend server 10/ab " ?> /usr/local/nginx/html/ab/index.html?
- echo "This is backend server 30/ab" > /var/www/html/ab/index.html?
此時搜索192.168.140.20依次顯示This is backend server 10/ab、This is backend server 20/ab
一、什么是會話?
????????在計算機網絡和 Web 開發中,會話(Session) 指的是用戶與系統(通常是服務器)之間的一次連續交互過程,核心作用是記錄用戶的狀態信息,解決 HTTP 協議 “無狀態” 的問題。
二、為什么需要會話?
????????HTTP 協議本身是 “無狀態” 的:每次客戶端(如瀏覽器)向服務器發送請求時,服務器無法默認記住 “這個請求來自哪個用戶”“用戶之前做過什么操作”。例如:
- 你在電商網站登錄后,瀏覽商品、加入購物車,如果沒有會話,服務器會 “忘記” 你已登錄,也記不住你的購物車內容;
- 你在論壇發帖時,服務器需要知道 “你是誰” 才能關聯到你的賬號。
????????會話的出現,就是為了讓服務器 “記住” 用戶的狀態(如登錄信息、操作歷史、偏好設置等),讓交互更連貫。
????????會話的核心邏輯:會話的實現依賴 “會話標識(Session ID)”,流程大致如下:
- 創建會話:用戶第一次訪問服務器時,服務器生成一個唯一的 Session ID(如一串隨機字符串),并創建一個對應的 “會話空間”(存儲用戶狀態,如登錄狀態、購物車數據等);
- 傳遞標識:服務器將 Session ID 通過Cookie(主流方式)或 URL 參數返回給客戶端,客戶端后續請求時會自動攜帶這個 ID;
- 識別用戶:服務器收到請求后,通過 Session ID 找到對應的 “會話空間”,從而識別用戶身份和狀態,繼續處理請求(如確認 “已登錄”、讀取購物車內容);
- 銷毀會話:當用戶主動退出(點擊 “退出登錄”)或會話超時(如 30 分鐘未操作),服務器會刪除對應的會話數據,Session ID 失效。
二、什么是 “會話持久問題”?
????????在負載均衡(多后端服務器)環境中,用戶的請求會被分發到不同的服務器。但默認情況下,用戶的會話信息(如登錄狀態、臨時數據)是存儲在單個服務器的本地內存 / 文件中的。這會導致一個問題:
- 用戶第一次請求被分到服務器 A,登錄狀態保存在 A 的本地;
- 第二次請求被負載均衡器分到服務器 B,B 沒有用戶的登錄狀態,用戶需要重新登錄。
這種 “用戶狀態無法在多服務器間共享” 的問題,就是會話持久問題。
三、如何解決?—— 會話共享
????????核心思路:將用戶的會話信息從 “單服務器本地存儲” 遷移到 “所有服務器都能訪問的集中式存儲”,讓所有后端服務器都能讀取到相同的會話數據。
NoSQL 數據庫非關系型數據庫(如 Redis、MongoDB、memached)實現會話共享。
- 高性能:NoSQL(尤其是 Redis)支持內存存儲,讀寫速度極快,適合會話這種高頻訪問的數據;(對內存要求高)
- 鍵值結構適配:會話數據通常是 “會話 ID→用戶信息” 的鍵值對形式,與 NoSQL 的存儲模型天然匹配;
- 支持過期時間:可直接為會話數據設置過期時間(如 2 小時),自動清理無效會話,無需手動維護;
- 高可用:NoSQL 可通過集群部署(如 Redis 主從、哨兵)避免單點故障,確保會話數據不丟失。
四、基于 NoSQL 的會話共享流程
以最常用的 Redis 為例,完整流程如下:
用戶首次登錄:
- 用戶在瀏覽器輸入賬號密碼,請求被負載均衡器分發到某臺后端服務器(如服務器 A);
- 服務器 A 驗證通過后,生成一個唯一的會話 ID(如session_id=xxxx);
- 將用戶的會話數據(如用戶 ID、登錄時間、權限等)以session_id為鍵,存儲到 Redis 中(例如:SET session:xxxx "{user_id:100, status:login}" EX 7200,設置 2 小時過期);
- 服務器 A 將session_id通過 Cookie 或 URL 參數返回給客戶端(瀏覽器),客戶端后續請求會自動攜帶該session_id。
用戶后續請求:
- 客戶端攜帶 session_id 發送請求,被負載均衡器分發到任意服務器(如服務器 B);
- 服務器 B 收到請求后,從 Redis 中通過session_id查詢會話數據(GET session:xxxx);
- 若查詢到有效數據,說明用戶已登錄,直接返回請求結果;若未查詢到(過期或無效),則要求用戶重新登錄。
會話過期 / 注銷:
- 若用戶主動退出登錄,服務器刪除 Redis 中對應的session_id數據;
- 若用戶長時間未操作,Redis 會自動根據預設的過期時間刪除會話數據,實現 “自動登出”。