開始使用nginx的實戰負載平衡指南

許多開發者只把nginx當作「反向代理 + 靜態文件服務」使用,但實際上nginx是一個相當強大的軟體負載平衡器。如果你是同時管理伺服器的開發者,僅靠熟練使用nginx,就能在流量高峰時顯著提升服務的穩定性與效能。

本文針對初學者到中級開發者,一次性整理以下內容:

  • 負載平衡概念
  • nginx負載平衡設定方法
  • 演算法(round robin、least_conn、ip_hash 等)
  • 健康檢查(Health Check)
  • 常用選項

1. 什麼是負載平衡?



負載平衡(load balancing)簡單來說,就是:

「將請求平均分配到多台伺服器,避免單台過載」

為什麼需要?

  1. 防止流量暴增 * 即使在高峰時段,單台伺服器也不會因為請求過多而宕機。
  2. 擴展性(Scale Out) * 透過水平擴充(多台伺服器)提升處理量,而非單台升級硬體。
  3. 容錯(高可用) * 即使一台伺服器失效,流量仍可轉發到其他伺服器,服務持續運作。

nginx 在負載平衡中的角色

典型架構如下:

客戶端 → nginx(負載平衡器 / 反向代理) → 多台應用伺服器

nginx 接收請求後,將其轉發到後端的某台應用伺服器。


2. 理解 nginx 負載平衡的基本結構

在 nginx 設定中,負載平衡主要分為兩個部分:

  1. upstream 區塊: * 定義「後端伺服器池」
  2. server / location 區塊: * 指定進來的請求應該轉發到哪個 upstream

先看最簡單的範例。

http {
    upstream app_backend {
        server 10.0.0.101:3000;
        server 10.0.0.102:3000;
    }

    server {
        listen 80;
        server_name example.com;

        location / {
            proxy_pass http://app_backend;

            # 代理基本標頭
            proxy_set_header Host $host;
            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;
        }
    }
}

這個設定的意義

  • upstream app_backend:將 10.0.0.101:300010.0.0.102:3000 兩台伺服器視為同一個「池」
  • proxy_pass http://app_backend;:將客戶端請求轉發到 app_backend 池中的某台伺服器
  • 若未指定演算法,預設使用 round robin(輪詢)

3. 負載平衡演算法種類



nginx 提供多種分配策略,根據實際情況選擇最合適的演算法。

3.1 基本:Round Robin(輪詢)

設定:不寫任何指令即為預設

upstream app_backend {
    server 10.0.0.101:3000;
    server 10.0.0.102:3000;
}
  • 第一個請求 → 伺服器1
  • 第二個請求 → 伺服器2
  • 第三個請求 → 再回到伺服器1 …

優點:簡單,適用於大多數情況 缺點:不考慮各伺服器目前的負載


3.2 least_conn(最少連線)

upstream app_backend {
    least_conn;
    server 10.0.0.101:3000;
    server 10.0.0.102:3000;
}
  • 將新請求送到「目前連線數最少」的伺服器
  • 適用於請求處理時間差異較大的服務(例如某些 API 請求耗時較長)

建議使用情境

  • 某些請求耗時長,其他請求短
  • 伺服器規格相近,但請求模式不均勻

3.3 ip_hash(相同 IP 同一台伺服器)

upstream app_backend {
    ip_hash;
    server 10.0.0.101:3000;
    server 10.0.0.102:3000;
}
  • 以客戶端 IP 做哈希,始終將同一 IP 的請求導向同一台伺服器
  • 適合需要「粘性 Session」的舊式應用(將 Session 存於伺服器記憶體)

優點:同一使用者請求始終到同一台伺服器 缺點:新增/移除伺服器時,哈希可能改變,導致大量使用者重新映射;若使用代理(Cloudflare、ELB 等)無法取得真實 IP,則無效


3.4 基於權重(weight)的分配

當伺服器規格不同,想將更多流量分配給性能較好的伺服器時可使用。

upstream app_backend {
    server 10.0.0.101:3000 weight=3;
    server 10.0.0.102:3000 weight=1;
}
  • 伺服器1 : 伺服器2 = 3 : 1 的比例分配
  • 適合新加入的高規格伺服器先行使用

4. 健康檢查(Health Check)與失效伺服器處理

為了讓負載平衡器真正「聰明」,必須能自動將失效伺服器剔除。

nginx 開源版預設支援 被動健康檢查(passive health check)

4.1 max_fails / fail_timeout

upstream app_backend {
    server 10.0.0.101:3000 max_fails=3 fail_timeout=30s;
    server 10.0.0.102:3000 max_fails=3 fail_timeout=30s;
}
  • max_fails=3:連續三次失敗即視為「異常」
  • fail_timeout=30s:在 30 秒內不再將流量送往該伺服器;之後若再次成功則重新使用

「失敗」通常指 502/503/504 回應、連線失敗等。


4.2 proxy_next_upstream

可設定在何種情況下將請求轉發到下一台伺服器。

location / {
    proxy_pass http://app_backend;
    proxy_next_upstream error timeout http_502 http_503 http_504;
}
  • 指定錯誤發生時重試下一台伺服器
  • 過度重試會增加延遲,請僅在必要時使用

5. 實戰範例:簡易 Web 服務負載平衡

假設你有兩台 Node.js 應用伺服器,執行於 3000 端口:

  • 10.0.0.101:3000
  • 10.0.0.102:3000

5.1 nginx 設定範例

http {
    upstream app_backend {
        least_conn;

        server 10.0.0.101:3000 max_fails=3 fail_timeout=30s;
        server 10.0.0.102:3000 max_fails=3 fail_timeout=30s;
    }

    server {
        listen 80;
        server_name myservice.com;

        # 客戶端 → nginx → Node.js 伺服器
        location / {
            proxy_pass http://app_backend;

            proxy_set_header Host $host;
            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;

            proxy_read_timeout 60s;
            proxy_connect_timeout 5s;
            proxy_send_timeout 10s;
        }
    }
}

重新載入 nginx 後:

  • 所有進入 myservice.com 的請求會被轉發到連線數最少的 Node.js 伺服器
  • 若某台伺服器連續失敗,將在一段時間內自動排除

6. HTTPS(SSL)終止 + 負載平衡

在生產環境中,HTTPS 已成為標準。nginx 常被用作 SSL 終止(termination) 的節點。

http {
    upstream app_backend {
        least_conn;
        server 10.0.0.101:3000;
        server 10.0.0.102:3000;
    }

    server {
        listen 443 ssl;
        server_name myservice.com;

        ssl_certificate     /etc/letsencrypt/live/myservice.com/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/myservice.com/privkey.pem;

        location / {
            proxy_pass http://app_backend;

            proxy_set_header Host $host;
            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 80;
        server_name myservice.com;
        return 301 https://$host$request_uri;
    }
}
  • 客戶端與 nginx 之間使用 HTTPS
  • nginx 與後端伺服器之間使用 HTTP(內部網路通常如此)

7. Session 問題:粘性 Session 必須嗎?

舊式應用常將 Session 存於伺服器記憶體,這時「同一使用者必須送到同一台伺服器」的需求很高。

nginx 可用 ip_hash 簡單解決,但現代做法多採用:

  • 將 Session 存於 Redis 等外部儲存
  • 使用 JWT,讓應用無狀態(stateless)

若能在應用層移除狀態,負載平衡器就只需負責流量分配,維運與擴充更為順暢。


8. 常用調優點

8.1 keepalive 設定

重複使用後端連線可提升效能。

upstream app_backend {
    least_conn;
    server 10.0.0.101:3000;
    server 10.0.0.102:3000;

    keepalive 32;
}

server {
    location / {
        proxy_pass http://app_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
    }
}
  • keepalive 32;:每個 worker 允許最多 32 個 keepalive 連線
  • 減少 TCP 連線建立的延遲與 CPU 負擔

8.2 緩衝區 & 時間設定

對於大型回應或後端較慢的情況,緩衝與時間設定同樣重要。

location / {
    proxy_pass http://app_backend;

    proxy_buffering on;
    proxy_buffers 16 16k;
    proxy_busy_buffers_size 64k;

    proxy_read_timeout 60s;
    proxy_send_timeout 60s;
}
  • proxy_read_timeout 設得太短會導致 504 Gateway Timeout
  • 依實際流量與後端效能調整

9. nginx 負載平衡導入策略(分階段)

若服務已運行且集中於單台伺服器,建議按以下步驟逐步擴充。

  1. 第一階段:先將 nginx 作為反向代理 * 客戶端 → nginx → 現有單台應用伺服器 * 同時啟用 SSL 終止、靜態檔案服務、快取等功能
  2. 第二階段:複製應用伺服器並配置 upstream * 複製現有伺服器或新增新伺服器,確保資料同步 * 在 upstream 中加入兩台伺服器,開始負載平衡
  3. 第三階段:健康檢查 + 監控 * 設定 max_failsfail_timeoutproxy_next_upstream * 引入日誌/指標收集(如 Prometheus + Grafana、ELK 等)
  4. 第四階段:演算法與細部調優 * 根據流量模式選擇 least_connweight * 調整 keepalive、緩衝、時間等參數

結語

nginx 不僅僅是「反向代理」;其負載平衡功能非常完善。只要掌握以下幾點:

  • upstream 定義伺服器池
  • 選擇合適的負載平衡演算法(round robin / least_conn / ip_hash / weight)
  • 配置健康檢查與重試策略,確保失效伺服器自動剔除
  • 在生產環境中使用 HTTPS 終止,保持內部通訊簡單

理解並實踐上述內容後,當你面臨「流量增長,單台伺服器是否足夠?」的疑問時,就能自信地使用 nginx 建立更穩定、更高效的基礎設施。

image