【Nginx】負載均衡

changwan發表於2024-06-13

一、工作原理

nginx的高效能主要是因為

1、事件驅動架構

Nginx採用事件驅動的非阻塞方式處理請求,主要利用了作業系統提供的多路複用機制,透過非同步非阻塞的方式處理大量併發請求,減少了執行緒切換和資源消耗,提高了併發處理能力和系統的穩定性。

2、事件迴圈

事件迴圈機制是核心的工作模式之一。它透過單執行緒的方式處理事件,包括等待事件、處理事件和繼續迴圈。在等待事件時,Nginx並不會像傳統多執行緒模型那樣阻塞等待,而是透過事件通知機制在有事件發生時再進行處理,這樣可以充分利用CPU資源,提升系統的效率和效能。

3、多程序

Nginx可以透過配置檔案中的worker_processes選項來啟動多個程序來處理請求。每個程序都有自己獨立的事件迴圈和資源管理,程序之間沒有共享狀態,這種設計可以避免單點故障,提高系統的可靠性和穩定性。並且Nginx的多程序模型使得它能夠更好地利用多核CPU,透過並行處理請求來提高整體的處理能力。

二、反向代理

server {
    listen 80;  
    server_name example.com;  
    root /root/build/;#靜態資源地址
    index index.html;    

    location /api/server/ {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For
    }
}

例如在這個例子中,設定了index目錄和靜態資源目錄。並且設定了域名訪問。很大了保證了伺服器的安全性。在下面的反向代理配置中,透過正規表示式將/api/server/開頭的對映到http://localhost:8080這個地址。

whiteboard_exported_image.png

三、負載均衡

負載均衡也就是透過反向代理到不同的服務,保證服務的可用性。多用於在分散式系統中。例如某個系統分佈在100個伺服器上,當某幾臺伺服器崩潰時,會代理到其他伺服器,不會影響系統的執行。更好的實現橫向擴充套件。

例如一個簡單的get請求程式碼

import tornado.ioloop
import tornado.web

class MainHandler(tornado.web.RequestHandler):
    def get(self):
        self.write("Hello, Tornado!") 

def make_app():
    return tornado.web.Application([
        (r"/", MainHandler),
    ])

if __name__ == "__main__":
    app = make_app()
    app.listen(8888) 
    print("Server running on http://localhost:8888")
    tornado.ioloop.IOLoop.current().start()  

具體的負載均衡演算法

1、輪詢

nginx的均衡預設演算法:直接基於事件迴圈。類似於排隊,一個一個來,例如第一個請求分發給第一個服務,第二個就分發給第二個服務,以此類推。缺點:沒有具體情況具體分析,某些情況下的請求會導致負載很高。

upstream tornado_servers {
    server 192.168.31.158:8888;
    server localhost:8888;
}

server {
    listen 80;
    server_name 192.168.62.132; 

    location / {
        proxy_pass http://tornado_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    location /nginx_status {
    stub_status on;
    access_log off;
    allow 192.168.62.0/24;  # 允許訪問的IP地址,根據需要調整
    deny all;         # 禁止其他IP地址訪問
    }    
}

將上述訪問執行在兩個不同的伺服器上,預設的輪詢會每個伺服器都請求一次,除非有一臺掉線,否則nginx會均分請求。

下面行的localhost塊b表示新的匹配規則,用於檢視nginx當前的連線數和請求統計資訊。

server accepts handled requests

Active connections: 1

表示當前活躍的連線數,即正在與Nginx伺服器建立通訊的客戶端連線數量。

server accepts handled requests

accepts: 表示Nginx已經接受的連線總數。

handled: 表示Nginx已經處理的連線總數。

requests: 表示Nginx已經處理的請求總數。

Reading: 0 Writing: 1 Waiting: 0

Reading: 正在讀取客戶端請求的數量。

Writing: 正在向客戶端傳送響應的數量。

Waiting: 當前空閒的客戶端連線數,等待處理請求

2、最少連線

會將請求分配給連線最少的服務,保證系統的整體效能。缺點是沒有具體情況具體分析,沒有考慮負載情況,不是請求越多負載越大。

upstream tornado_servers {
    least_conn;  # 使用最少連線數演算法
    server 192.168.31.158:8888;
    server localhost:8888;
}

server {
    listen 80;
    server_name 192.168.62.132;  

    location / {
        proxy_pass http://tornado_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

least_conn欄位表示使用最少連線演算法。

3、IP雜湊

透過客戶端的IP地址的雜湊值分配給特定的伺服器,如果下一次請求的IP雜湊值與之前一樣,那麼依然會請求到之前的伺服器。如果不一樣那麼為新的伺服器建立新的雜湊值。這樣避免了伺服器的切換開銷,保持了會話的一致性。但是這樣的缺點是同一個客戶端的請求無法做到負載均衡。

upstream tornado_servers {
    ip_hash;  # 使用IP雜湊演算法
    server 192.168.31.158:8888;
    server localhost:8888;
}

server {
    listen 80;
    server_name 192.168.62.132;  

    location / {
        proxy_pass http://tornado_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    location /nginx_status {
    stub_status on;
    access_log off;
    allow 192.168.62.0/24;  # 允許訪問的IP地址,根據需要調整
    deny all;         # 禁止其他IP地址訪問
    }
}

4、加權輪詢

在輪詢的基礎上為每個伺服器加上一個權重值,每個伺服器的承受連線數量。在輪詢的情況下再次考慮權重值。例如兩臺伺服器,伺服器A、B的權重分別為5,3輪詢流程為:

第一次請求:伺服器A處理請求

第二次請求:伺服器B處理請求

第三次請求:伺服器A處理請求

第四次請求:伺服器A處理請求

第五次請求:伺服器A處理請求

第六次請求:伺服器B處理請求

upstream tornado_servers {
    server 192.168.31.158:8888 weight=5;
    server localhost:8888 weight=3;
}

server {
    listen 80;
    server_name 192.168.62.132; 

    location / {
        proxy_pass http://tornado_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    location /nginx_status {
    stub_status on;
    access_log off;
    allow 192.168.62.0/24;  # 允許訪問的IP地址,根據需要調整
    deny all;         # 禁止其他IP地址訪問
    }
}

5、加權最小連線

在最小連線的演算法基礎上,加上權重值。這時候需要根據連線數量和權重值來評估目標伺服器。

例如伺服器A、B、C。權重值分別為5、3、2。連線數分別為10、5、3.

計算加權連線數:

伺服器A:10/5=2

伺服器B:5/3=1.67

伺服器C:3/2=1.5

那麼根據加權連線數,最小加權連線數為1.5。那麼會代理到伺服器C

upstream tornado_servers {
    least_conn;  # 使用最少連線數演算法
    server 192.168.31.158:8888 weight=5;
    server localhost:8888 weight=3;
}

server {
    listen 80;
    server_name 192.168.62.132; 

    location / {
        proxy_pass http://tornado_servers;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    location /nginx_status {
    stub_status on;
    access_log off;
    allow 192.168.62.0/24;  # 允許訪問的IP地址,根據需要調整
    deny all;         # 禁止其他IP地址訪問
    }
}

四、總結

反向代理就像是位於使用者和真實伺服器之間的一座橋樑,它接收使用者的請求並將其轉發到後端的多臺伺服器上。這種配置不僅隱藏了真實伺服器的資訊,還能提供安全性和負載均衡功能。負載均衡透過智慧地分發請求到不同的伺服器,確保每臺伺服器的負載相對平衡,從而提高整體效能和可靠性。這種結合能夠有效地處理高併發請求,保證系統在壓力下仍能保持穩定執行。

相關文章