ตั้งค่า Nginx Load Balancing เพื่อกระจาย Traffic
Load Balancing คือเทคนิคที่ช่วยกระจาย Traffic จากผู้ใช้ออกไปยังหลาย Server พร้อมกัน ทำให้ระบบรองรับผู้ใช้ได้มากขึ้น ลด Downtime และป้องกันไม่ให้ Server ใด Server หนึ่งรับภาระหนักเกินไป ในบทความนี้จะสอนการตั้งค่า Nginx ให้ทำหน้าที่เป็น Load Balancer แบบ Reverse Proxy กระจาย Request ไปยัง Backend Server หลายตัวด้วยวิธีต่าง ๆ
สถาปัตยกรรมที่ใช้ในบทความนี้
ในตัวอย่างนี้เราจะมี Server ทั้งหมด 3 เครื่อง ได้แก่
- Load Balancer — IP: 10.0.0.1 (Nginx ติดตั้งอยู่ที่นี่ รับ Request จากภายนอก)
- Backend 1 — IP: 10.0.0.11 (รัน Web Application)
- Backend 2 — IP: 10.0.0.12 (รัน Web Application)
ติดตั้ง Nginx บนเครื่อง Load Balancer
เชื่อมต่อเข้า Load Balancer แล้วติดตั้ง Nginx ด้วยคำสั่งต่อไปนี้
# อัปเดต Package List
sudo apt update && sudo apt upgrade -y
# ติดตั้ง Nginx
sudo apt install nginx -y
# ตรวจสอบ Version
nginx -v
# เปิดใช้งาน Nginx ให้ Start อัตโนมัติ
sudo systemctl enable nginx
sudo systemctl start nginx
ทำความเข้าใจ Load Balancing Algorithm ทั้ง 3 แบบ
1. Round Robin (ค่าเริ่มต้น)
Nginx จะส่ง Request ไปยัง Backend แต่ละตัวแบบวนเวียน ตัวที่ 1 → ตัวที่ 2 → ตัวที่ 1 → ตัวที่ 2 เหมาะกับ Backend ที่มีสเปกใกล้เคียงกันและ Request แต่ละอันใช้เวลาประมวลผลพอ ๆ กัน
2. Least Connections
Nginx จะส่ง Request ใหม่ไปยัง Backend ที่มี Active Connection น้อยที่สุดในขณะนั้น เหมาะมากสำหรับงานที่แต่ละ Request ใช้เวลาไม่เท่ากัน เช่น File Upload หรือ API ที่มี Response Time แตกต่างกันมาก
3. IP Hash
Nginx คำนวณ Hash จาก IP Address ของ Client แล้วส่งไปยัง Backend ตัวเดิมเสมอ ทำให้ผู้ใช้คนเดิมถูก Route ไปหา Server เดิมตลอด เหมาะกับ Application ที่เก็บ Session ไว้บน Server (Sticky Session)
ตั้งค่า Round Robin Load Balancing
สร้างไฟล์ Config ใหม่สำหรับ Load Balancer
sudo nano /etc/nginx/conf.d/loadbalancer.conf
ใส่ Config ต่อไปนี้
upstream backend_pool {
server 10.0.0.11:80;
server 10.0.0.12:80;
}
server {
listen 80;
server_name yourdomain.com;
location / {
proxy_pass http://backend_pool;
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;
}
}
จากนั้นตรวจสอบ Config และ Reload Nginx
sudo nginx -t
sudo systemctl reload nginx
ตั้งค่า Least Connections
เพียงเพิ่ม least_conn; เข้าไปใน Block upstream
upstream backend_pool {
least_conn;
server 10.0.0.11:80;
server 10.0.0.12:80;
}
ตั้งค่า IP Hash
เพิ่ม ip_hash; แทน
upstream backend_pool {
ip_hash;
server 10.0.0.11:80;
server 10.0.0.12:80;
}
กำหนด Weight ให้แต่ละ Backend
ถ้า Backend แต่ละตัวมีสเปกไม่เท่ากัน สามารถกำหนดค่า Weight เพื่อให้ Backend ที่แรงกว่ารับ Traffic มากกว่าได้
upstream backend_pool {
server 10.0.0.11:80 weight=3; # รับ 3 ส่วน
server 10.0.0.12:80 weight=1; # รับ 1 ส่วน
}
ในตัวอย่างนี้ Backend 1 จะรับ Request 3 ใน 4 ครั้ง ส่วน Backend 2 รับ 1 ใน 4 ครั้ง
ตั้งค่า Health Check และ Failover
Nginx สามารถกำหนดให้ระบบ Mark Backend ที่ล้มเหลวว่า "ออฟไลน์" ชั่วคราวได้ด้วย Directive max_fails และ fail_timeout
upstream backend_pool {
least_conn;
server 10.0.0.11:80 max_fails=3 fail_timeout=30s;
server 10.0.0.12:80 max_fails=3 fail_timeout=30s;
}
- max_fails=3 — ถ้าเชื่อมต่อล้มเหลว 3 ครั้งติดต่อกัน ให้ถือว่า Backend ตัวนั้นล้มเหลว
- fail_timeout=30s — ระยะเวลาที่ Nginx จะรอก่อนลองส่ง Request ไปใหม่ (30 วินาที)
นอกจากนี้ยังสามารถเพิ่ม Backup Server สำหรับใช้เมื่อ Backend หลักทั้งหมดล้มเหลว
upstream backend_pool {
server 10.0.0.11:80;
server 10.0.0.12:80;
server 10.0.0.99:80 backup; # ใช้เมื่อตัวหลักทั้งสองล้มเหลว
}
เพิ่ม Timeout และ Buffer Settings
ปรับค่า Proxy Timeout ให้เหมาะสมกับ Application โดยแก้ไขในส่วน location /
location / {
proxy_pass http://backend_pool;
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_connect_timeout 10s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering on;
proxy_buffer_size 16k;
proxy_buffers 4 16k;
}
เปิดใช้ HTTPS กับ Load Balancer
ติดตั้ง Certbot เพื่อขอ SSL Certificate จาก Let's Encrypt
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com
Certbot จะแก้ไข Config ให้อัตโนมัติ เพิ่ม Redirect HTTP → HTTPS และ SSL Certificate ให้เรียบร้อย
ทดสอบ Load Balancing
ให้ Backend แต่ละตัว Return ค่าที่แตกต่างกันเพื่อยืนยันว่า Traffic ถูกกระจายจริง
# บน Backend 1 (10.0.0.11)
echo "Response from Backend 1" | sudo tee /var/www/html/index.html
# บน Backend 2 (10.0.0.12)
echo "Response from Backend 2" | sudo tee /var/www/html/index.html
จากนั้นทดสอบโดยใช้ curl บนเครื่อง Client
for i in {1..6}; do
curl -s http://yourdomain.com/
done
ผลลัพธ์ที่ควรได้ (Round Robin)
Response from Backend 1
Response from Backend 2
Response from Backend 1
Response from Backend 2
Response from Backend 1
Response from Backend 2
ตรวจสอบ Log และ Monitor
ดู Access Log เพื่อตรวจสอบว่า Request ถูกส่งไปยัง Backend ไหน
sudo tail -f /var/log/nginx/access.log
เพิ่ม Log Format พิเศษเพื่อแสดง Upstream ที่ถูกเลือก
# เพิ่มใน /etc/nginx/nginx.conf ใน block http {}
log_format upstream_log '$remote_addr - $upstream_addr [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
แล้วระบุ Format ใน access_log
access_log /var/log/nginx/upstream.log upstream_log;
สรุป
การตั้งค่า Nginx Load Balancing ช่วยให้ระบบของคุณรองรับผู้ใช้ได้มากขึ้นและทนทานต่อความล้มเหลวของ Backend Server แต่ละตัว ขอสรุป Checklist ที่ควรทำก่อน Go Live
- ติดตั้ง Nginx บน Load Balancer และสร้างไฟล์ Config ใน
/etc/nginx/conf.d/ - เลือก Algorithm ให้เหมาะกับงาน — Round Robin สำหรับ Request ที่ใช้เวลาเท่ากัน, Least Connections สำหรับงานที่ Response Time ต่างกัน, IP Hash สำหรับ Sticky Session
- ตั้งค่า
max_failsและfail_timeoutเพื่อให้ระบบ Failover ได้อัตโนมัติ - เปิด HTTPS ด้วย Certbot และใช้ SSL Termination ที่ Load Balancer
- ทดสอบด้วย
curlและตรวจสอบ Log ว่า Traffic กระจายไปยัง Backend ทุกตัวจริง - ย้าย Session ไปเก็บใน Redis หรือ Database กลาง เพื่อลดการพึ่งพา IP Hash
เมื่อระบบโตขึ้น สามารถเพิ่ม Backend Server เข้าไปใน upstream Block ได้ทันทีโดยไม่ต้องหยุด Service โดย Reload Nginx เพียงครั้งเดียว ก็พร้อมรับ Traffic บน Backend ตัวใหม่ได้เลย
ตรวจสอบว่า Load Balancing ทำงานถูกต้อง
# ตรวจสอบ Nginx config syntax
nginx -t
# ทดสอบว่า traffic กระจายไปทั้งสอง backend
for i in {1..6}; do curl -s http://yourdomain.com/; done
# ควรสลับระหว่าง Backend 1 และ Backend 2
# ดู upstream log แบบ real-time
tail -f /var/log/nginx/upstream.log
# ตรวจสอบ backend ที่ active
curl http://localhost/nginx_status # ถ้าเปิด stub_status ไว้
add_header X-Served-By $upstream_addr; ใน location block ระหว่าง debug เพื่อดูใน response header ว่า request ถูกส่งไป backend ไหน — อย่าลืมลบออกก่อน production
แก้ปัญหาที่พบบ่อย
Error: "502 Bad Gateway" จาก load balancer
Backend server ไม่ตอบสนอง หรือ Nginx ไม่สามารถเชื่อมต่อ backend ได้ ตรวจสอบ:
# ตรวจสอบว่า backend service รันอยู่
curl -s http://10.0.0.11/ # ทดสอบตรง ๆ ที่ backend
# ดู error log ของ Nginx
tail -50 /var/log/nginx/error.log
# ตรวจสอบ firewall ของ backend
# Backend ต้องเปิด port 80 จาก IP ของ load balancer
Error: Traffic ไปแต่ backend เดียว ไม่กระจาย
มักเกิดจาก browser cache หรือ Nginx proxy cache ที่ทำให้ request เดิมไปหา backend เดิม:
# ทดสอบด้วย curl แทน browser เสมอ
for i in {1..4}; do curl -s -o /dev/null -w "%{http_code} %{time_total}\n" http://yourdomain.com/; done
# ตรวจสอบว่าไม่มี proxy_cache เปิดอยู่
grep -r "proxy_cache" /etc/nginx/conf.d/
Error: Session หายเมื่อ user ถูก route ไป backend อื่น
Application เก็บ session ใน local file/memory ทำให้ backend ต่างตัวไม่รู้จัก session นั้น:
# วิธีแก้ระยะสั้น: ใช้ ip_hash (sticky session)
upstream backend_pool {
ip_hash;
server 10.0.0.11:80;
server 10.0.0.12:80;
}
# วิธีแก้ระยะยาว: ย้าย session ไป Redis กลาง
# WordPress: ติดตั้ง WP Redis Object Cache plugin
# Laravel: SESSION_DRIVER=redis ใน .env
Error: Backend หนึ่งตัวล้มเหลว แต่ load balancer ยังส่ง traffic ไปอยู่
ต้องตั้ง max_fails และ fail_timeout ให้ถูกต้องใน upstream config:
upstream backend_pool {
server 10.0.0.11:80 max_fails=3 fail_timeout=30s;
server 10.0.0.12:80 max_fails=3 fail_timeout=30s;
}
# หลัง reload Nginx จะ mark backend ว่า down หลัง fail 3 ครั้ง
# และลองใหม่หลัง 30 วินาที
Error: "upstream timed out (110: Connection timed out)"
Backend ช้าเกินกว่า timeout ที่ตั้งไว้ ให้เพิ่ม read timeout หรือ debug ว่า backend ช้าเพราะอะไร:
location / {
proxy_pass http://backend_pool;
proxy_read_timeout 120s; # เพิ่มจาก default 60s
proxy_connect_timeout 10s;
}
คำถามที่พบบ่อย
ต้องการ VPS กี่เครื่องสำหรับ load balancing?
ขั้นต่ำ 2 เครื่อง: 1 load balancer + 1 backend แต่ที่ทำให้ high availability จริงคือ 3 เครื่อง: 1 load balancer + 2 backend ถ้า backend ตัวหนึ่งล้มเหลว อีกตัวรับงานต่อได้ทันที สำหรับ production จริงควรมี load balancer 2 ตัวด้วย (HA Proxy pair)
load balancer ทำ SSL termination หมายความว่าอะไร?
SSL termination แปลว่า load balancer รับการ decrypt SSL จาก client แล้วส่ง HTTP ธรรมดาไป backend การ์ตั้ง SSL certificate ทำแค่ที่ load balancer ตัวเดียว backend ไม่ต้องมี certificate เลย ทำให้จัดการ certificate ง่ายขึ้นมาก และ backend ไม่เปลือง CPU กับ SSL handshake
เพิ่ม backend server ตัวใหม่ต้อง restart Nginx ไหม?
แค่ reload เท่านั้น เพิ่ม IP ใหม่ใน upstream block แล้ว nginx -t && systemctl reload nginx — reload ไม่ kill connection ที่กำลังทำงานอยู่ ต่างจาก restart ที่จะ drop active connections ทั้งหมด