網關中間件-Nginx(一)
一、Nginx介紹
1.nginx是一個高性能HTTP伺服器,反向代理伺服器,郵件代理伺服器,TCP/UDP反向代理伺服器.
2.nginx處理請求是非同步非阻塞的,在高並發下nginx 能保持低資源低消耗高性能,主要用在集群系統中用於支援負載均衡.
3.nginx對靜態文件的處理速度也相當快,也可以用於前端站點的伺服器.
二、為什麼要使用Nginx?
單個系統主要用於處理客戶端請求,一個系統處理客戶端的請求量是有限的,當客戶端的並發量超過了系統的處理能力的時候,就會導致伺服器性能降低,速度變慢,直接影響用戶體驗,所以為了提升性能,我們會創建多個服務實例,形成集群系統
用於保證高可用
那麼什麼樣的系統業務適合使用集群系統呢?我覺得主要從2個方面來看,第一請求人數多,導致次數多,第二請求量密集,例如我們近兩年常用的防疫健康碼
查詢,我們排除與其他的業務系統接入的因素,可以說他的99%針對用戶的業務其實就是查詢,而且並發量和請求數也是非常龐大的,所以就很適合使用集群系統。
三、查詢分流Nginx原理
1.模組化設計
高度模組化的設計是 Nginx的架構基礎。在Nginx中,除了少量的核心程式碼,其他一切皆為模組,所有模組間是分層次、分類別的,Nginx 官方共有五大類型的模組:核心模組
、配置模組
、事件模組
、HTTP模組
、mail模組
,5種模組中,配置模組
和核心模組
是與 Nginx 框架密切相關的。而事件模組則是 HTTP 模組和 mail 模組的基礎。HTTP 模組
和 mail 模組
的「地位」類似,它們都是更關注於應用層面
並且引用基礎核心模組。
2.多進程模型
與Memcached的經典多執行緒模型相比,Nginx是經典的多進程模型,Nginx啟動後在後台運行,後台進程包含一個master進程和多個worker進程,可以在配置中設置工作進程數,一般根據伺服器的Cpu核心數,來決定工作進程數是多少,例如我的電腦核心數是12,那可以在配置文件中設置worker_processes為12,那麼在進程中可以看到 一個13個nginx運行實例。
3.事件驅動架構
處理請求事件時,Nginx 的事件消費者只是被事件分發者進程短期調用而已,這種設計使得網路性能、用戶感知的請求時延都得到了提升,每個用戶的請求所產生的事件會及時響應,整個伺服器的網路吞吐量都會由於事件的及時響應而增大。當然,這也帶來一定的要求,即每個事件消費者都不能有阻塞行為,否則將會由於長時間佔用事件分發者進程而導致其他事件得不到及時響應,Nginx 的非阻塞特性就是由於它的模組都是滿足這個要求,其實Nginx最佳的部署應該在linux ,linux的io及事件驅動優於windows,我們可以通過配置文件中設置events的數量表示當前的nginx能處理多少個請求,這個沒有一個絕對的標準,可以基於服務的性能和本身業務需求而定。
4.虛擬主機、反向代理、負載均衡
1.虛擬主機就是為了對所有應用系統進行反向代理。
2.反向代理是指代理後端伺服器,正向代理代表代理客戶端。
3.負載均衡將流量均分到指定後端實例。
四、落地Nginx
我們首先結合實際業務場景分析,然後對不同的業務用例進行落地實踐的方案選擇。
1.負載均衡業務實踐
1.首先我們應該準備一個業務系統,在這就用上面說的「健康碼查詢」業務,模擬一個查詢的服務,注意在這僅僅只是引用場景示例,不代表健康碼真實場景如此, 因為我沒有參與真正的防疫健康碼的開發和設計,也不了解它業務和技術架構上真正的複雜度,單純只是由此引入業務場景而已,如果您在閱讀時覺得這樣不合適,您可以把他當做你想當做的任何系統,或者忘記這件事,都是可以的
接下來我們應該下載Nginx作為我們的伺服器,在這裡我使用的是在Windows環境下的演示,其實不管在Linux或者Docker中部署都可以,但是開發在windows,所以基於Windows比較方便。
- 1.創建健康碼服務
- 2.下載nginx
2.我們應該創建服務集群,在這為了演示創建2個服務實例,然後使用nginx來進行負載均衡查詢分流
-
1.命令行啟動2個服務實例模擬集群,分別綁定埠8081和8082,其實真實環境不會只有2個實例或者在同一台伺服器上部署。
-
2.配置nginx的反向代理和負載均衡
worker_processes 1;
error_log logs/error.log info;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
access_log logs/access.log main;
sendfile on;
keepalive_timeout 65;
#虛擬主機
server{
listen 8080;
server_name localhost;
#配置反向代理
location / {
proxy_pass //HealthCode;
}
error_page 500 502 503 504 /50x.html;
}
}
#負載均衡配置
upstream HealthCode{
server localhost:8081;
server localhost:8082;
}
- 3.啟動nginx,並訪問虛擬伺服器
2.負載均衡業務場景分析
針對上面的業務,我們使用到nginx實現負載均衡,那對於我們來說,應該知道Nginx虛擬主機,是如何將我們的請求轉發到各個不同的服務實例的,下面結合業務用例來介紹Nginx中的各種負載均衡演算法
,並設置對應的配置文件節點。
1.輪訓演算法
根據字面理解就是輪訓處理 1 2 3 4 周而復始,適合伺服器處理能力相同的實例,也可以加入權重,指定輪詢幾率,weight和訪問比率成正比,用於伺服器性能不均的情況下,權重越高,在被訪問的概率越大,如下面分別是20%,80%。
#負載均衡配置
upstream HealthCode{
server localhost:8081;
server localhost:8082;
#server localhost:8081 weight=2;
#server localhost:8082 weight=8;
}
2.最小連接數演算法 least_conn
當客戶端給Nginx發送查詢健康碼的請求時,Nginx把請求轉發給8081和8082 ,如果8082 處理請求比較慢,會導致請求堆積在8082,那我們就需要解決請求堆積的問題,在這種場景下,我們可以把請求轉發給連接數較少的伺服器處理,能夠達到更好的負載均衡效果,使用least_conn演算法,在nginx配置文件中,負載均衡節點加入配置least_conn
#負載均衡配置
upstream HealthCode{
#配置最小連接數演算法
least_conn;
server localhost:8081;
server localhost:8082;
}
3. hash一致性演算法 ip_hash
由於查詢壓力過大,為了提升可用性,我們在服務端加入快取,例如3分鐘之內請求,就直接將快取的資訊丟出去,客戶端給Nginx發送查詢健康碼的請求時,Nginx把請求轉發給8081和8082,甚至更多實例,使用輪訓或者最小連接數時,會導致在快取的情況下命中率下降,基於這種快取狀態丟失
的情況,請求依然會給到沒有快取的服務實例,並去資料庫中去查詢數據,導致性能下降。
(當第一次請求發送到8081去查詢了資料庫,但是在8082 或者其他的節點沒有快取,如果使用輪訓演算法及其他演算法,會導致下次請求時,並不會訪問快取,所以叫快取命中率下降
)
在這種場景下我們應該使用Hash一致性演算法
,將某一個請求客戶端的ip地址與nginx的負載均衡中的某一個實例綁定。
#負載均衡配置
upstream HealthCode{
#配置iphash演算法
ip_hash;
server localhost:8081;
server localhost:8082;
}
4.容災策略
重試機制
1.當客戶端給Nginx發送查詢請求時,Nginx把請求轉發給8081和8082 ,如果轉發到8081的時候,8081伺服器被人拉閘,臨時宕機了,會導致請求失敗。如何保證請求成功?
在這種場景下我們應該使用nginx的失敗重試
機制,將某一個請求客戶端的ip地址與nginx的負載均衡中的某一個實例綁定。
#動態負載均衡配置
upstream HealthCode{
ip_hash;
#設置最大失敗次數2次,超時時間10s鍾
server localhost:8081 max_fails=2 fail_timeout=10s;
server localhost:8082 max_fails=2 fail_timeout=10s;
}
主機備份 backup
1.查詢時請求轉發給8081和8082 ,假設此時兩個實例同時宕機了,會導致系統不可用,在這種異常業務情況下,我們可以使用主機備份
來解決,注意在正常節點在運行時 ,備份節點是不工作的,如果使用ip_hash
將不會生效,因為ip和主機已經綁定。
#動態負載均衡配置
upstream HealthCode{
ip_hash;
server localhost:8081 max_fails=2 fail_timeout=10s;
server localhost:8082 max_fails=2 fail_timeout=10s;
#主機備份
server localhost:8083 backup;
}