Weighted Load Balancing #
Weight memungkinkan kita mengontrol seberapa banyak traffic yang diterima setiap server secara proporsional. Secara default semua server memiliki weight 1 — distribusi merata. Dengan weight, kita bisa mencerminkan perbedaan kapasitas hardware, melakukan canary deployment bertahap, atau menjalankan strategi blue-green deployment zero-downtime.
Cara Kerja Weight #
Weight adalah angka relatif. Yang penting bukan nilainya secara absolut, melainkan perbandingan antar server:
upstream app_servers {
server 10.0.0.1:3000 weight=3;
server 10.0.0.2:3000 weight=1;
}
Dari setiap 4 request:
- 3 request → Server 10.0.0.1 (weight 3)
- 1 request → Server 10.0.0.2 (weight 1)
weight=3 dan weight=1 menghasilkan distribusi yang identik dengan weight=6 dan weight=2, atau weight=30 dan weight=10. Nginx mendistribusikan berdasarkan proporsi.
Tanpa weight (atau weight=1), semua server mendapat distribusi yang sama:
weight=1, weight=1, weight=1 → 33.3%, 33.3%, 33.3%
weight=2, weight=1, weight=1 → 50%, 25%, 25%
weight=3, weight=2, weight=1 → 50%, 33.3%, 16.7%
weight=5, weight=3, weight=2 → 50%, 30%, 20%
Use Case 1: Server dengan Kapasitas Hardware Berbeda #
Skenario paling umum dalam dunia nyata: infrastruktur yang terdiri dari server dengan spesifikasi yang tidak seragam — karena upgrade bertahap, warisan dari era sebelumnya, atau penggunaan spot instance:
upstream production_cluster {
# Server generasi terbaru (high-end)
# 32 core, 128GB RAM, SSD NVMe
server 10.0.0.1:3000 weight=8;
# Server generasi menengah
# 16 core, 64GB RAM, SSD
server 10.0.0.2:3000 weight=4;
# Server lama yang masih digunakan
# 8 core, 32GB RAM, HDD
server 10.0.0.3:3000 weight=2;
# Server minimal (backup yang ikut melayani traffic normal)
# 4 core, 16GB RAM
server 10.0.0.4:3000 weight=1;
# Total: 15 bagian
# Server 1: 8/15 = 53% traffic
# Server 2: 4/15 = 27% traffic
# Server 3: 2/15 = 13% traffic
# Server 4: 1/15 = 7% traffic
keepalive 32;
zone production_upstream 128k;
}
Use Case 2: Canary Deployment #
Canary deployment adalah teknik merilis versi baru dengan mengirimkan sebagian kecil traffic terlebih dahulu untuk validasi sebelum full rollout. Weight adalah cara paling mudah mengimplementasikannya di Nginx:
flowchart LR
subgraph PHASE1["Tahap 1: Canary 5%"]
P1A["v1 weight=95\n(server 1, 2, 3)"]
P1B["v2 weight=5\n(server 4) canary"]
end
subgraph PHASE2["Tahap 2: Lanjut ke 20%"]
P2A["v1 weight=80\n(server 1, 2)"]
P2B["v2 weight=20\n(server 3, 4)"]
end
subgraph PHASE3["Tahap 3: Full Rollout"]
P3A["v2 weight=1\n(semua server)"]
end
PHASE1 --> PHASE2
PHASE2 --> PHASE3# Tahap 1: Mulai dengan 5% ke versi baru
upstream app_servers {
server 10.0.0.1:3000 weight=95; # v1 — production
server 10.0.0.2:3000 weight=95; # v1 — production
server 10.0.0.3:3000 weight=10; # v2 — canary (5% dari total)
}
# Cara mengubah weight tanpa downtime:
# 1. Edit konfigurasi
vim /etc/nginx/conf.d/myapp.conf
# Tahap 2: Naikkan ke 20%
# server 10.0.0.1:3000 weight=80; # v1
# server 10.0.0.2:3000 weight=20; # v2
# ...
# 2. Test konfigurasi
nginx -t
# 3. Reload tanpa downtime
nginx -s reload
Monitoring Canary dengan Logging #
http {
# Map versi berdasarkan upstream server yang dipilih
map $upstream_addr $app_version {
"~10\.0\.0\.[12]:" "v1";
"~10\.0\.0\.3:" "v2-canary";
default "unknown";
}
log_format canary_log '$remote_addr [$time_local] "$request" '
'$status $app_version $upstream_response_time';
server {
access_log /var/log/nginx/canary.log canary_log;
}
}
# Analisis error rate per versi
awk '{print $6, $5}' /var/log/nginx/canary.log | \
awk '{total[$1]++; if($2>=500) err[$1]++} END {for(k in total) print k, err[k]+0, total[k], (err[k]+0)/total[k]*100"%"}' | \
sort
# Output:
# v1 12 9823 0.12%
# v2-canary 8 489 1.63% ← error rate tinggi, rollback!
Use Case 3: Blue-Green Deployment Zero-Downtime #
Blue-green deployment menjalankan dua lingkungan produksi (blue = versi lama, green = versi baru) dan switch traffic sekaligus:
upstream app_servers {
# BLUE: versi yang saat ini aktif
server 10.0.0.1:3000 weight=1; # blue-1
server 10.0.0.2:3000 weight=1; # blue-2
# GREEN: versi baru — siap tapi belum terima traffic
server 10.0.0.3:3000 weight=0 backup; # green-1
server 10.0.0.4:3000 weight=0 backup; # green-2
}
Saat switch: edit konfigurasi, aktifkan green, nonaktifkan blue:
upstream app_servers {
# BLUE: dinonaktifkan
server 10.0.0.1:3000 down;
server 10.0.0.2:3000 down;
# GREEN: sekarang menerima semua traffic
server 10.0.0.3:3000 weight=1;
server 10.0.0.4:3000 weight=1;
}
Jika ada masalah, rollback instan dengan membalik konfigurasi lagi dan nginx -s reload.
Kombinasi Weight dengan Algoritma Lain #
Weighted Least Connections #
upstream app_servers {
least_conn;
# Server kuat mendapat lebih banyak koneksi sebelum dianggap "sibuk"
server 10.0.0.1:3000 weight=4; # 16 core
server 10.0.0.2:3000 weight=2; # 8 core
server 10.0.0.3:3000 weight=1; # 4 core
keepalive 32;
zone app_upstream 64k;
}
Formula pemilihan: koneksi_aktif / weight — server dengan nilai terkecil dipilih. Server berkapasitas lebih besar “membutuhkan” lebih banyak koneksi sebelum dianggap lebih sibuk dari server kecil.
Weighted IP Hash #
upstream app_servers {
ip_hash;
# Session persistence + weight
server 10.0.0.1:3000 weight=3;
server 10.0.0.2:3000 weight=1;
}
Dengan ip_hash + weight, pengguna masih dijamin ke server yang sama, tapi distribusi user antar server memperhitungkan weight. Server dengan weight lebih tinggi mendapat lebih banyak “slot” dalam ring hash.
Strategi Penerapan Weight untuk Auto-Scaling #
Di lingkungan cloud dengan auto-scaling, weight bisa dikelola secara programatik:
# Script: tambahkan server baru dengan weight rendah dulu (ramp-up)
add_server_with_ramp_up() {
local new_ip=$1
local config="/etc/nginx/conf.d/upstream.conf"
# Tambahkan dengan weight rendah (hati-hati, monitor dulu)
echo " server $new_ip:3000 weight=1;" >> $config
nginx -s reload
echo "Server $new_ip ditambahkan dengan weight=1 (5% traffic)"
sleep 300 # Monitor 5 menit
# Jika tidak ada alert, naikkan weight
sed -i "s/$new_ip:3000 weight=1/$new_ip:3000 weight=3/" $config
nginx -s reload
echo "Weight dinaikkan ke 3 (20% traffic)"
}
# Script: keluarkan server dengan graceful drain
remove_server_gracefully() {
local ip=$1
local config="/etc/nginx/conf.d/upstream.conf"
# Turunkan weight ke 0 dulu (drain traffic)
sed -i "s/$ip:3000 weight=[0-9]*/$ip:3000 weight=1/" $config
nginx -s reload
echo "Weight diturunkan ke 1"
sleep 60 # Tunggu request yang sedang berjalan selesai
# Tandai sebagai down
sed -i "s/$ip:3000 weight=1/$ip:3000 down/" $config
nginx -s reload
echo "Server $ip ditandai down, bisa di-terminate"
}
Tabel Rekomendasi Weight #
Beberapa rasio weight yang umum digunakan:
| Skenario | Rasio | Contoh |
|---|---|---|
| Server identik | 1:1:1 | weight=1 semua |
| Server 2x lebih kuat | 2:1 | weight=2, weight=1 |
| Mix generasi hardware | 4:2:1 | weight=4, weight=2, weight=1 |
| Canary 5% | 19:1 | weight=95, weight=5 |
| Canary 10% | 9:1 | weight=9, weight=1 |
| Canary 20% | 4:1 | weight=4, weight=1 |
| Canary 50% | 1:1 | weight=1, weight=1 |
Automasi Weight Management dalam CI/CD #
Untuk tim yang melakukan deployment sering, weight management bisa diotomasi sebagai bagian dari pipeline CI/CD:
#!/bin/bash
# deploy-canary.sh: Deploy versi baru sebagai canary
NEW_SERVER=$1 # IP server baru dengan versi baru
INITIAL_WEIGHT=5 # Mulai dengan 5%
CONFIG="/etc/nginx/conf.d/upstream.conf"
# Step 1: Tambahkan server baru dengan weight rendah
cat >> $CONFIG << EOF
server $NEW_SERVER:3000 weight=$INITIAL_WEIGHT; # canary v2
EOF
nginx -t && nginx -s reload
echo "Canary deployed: $NEW_SERVER dengan weight=$INITIAL_WEIGHT"
# Step 2: Monitor selama 10 menit
echo "Monitoring error rate selama 10 menit..."
sleep 600
# Hitung error rate canary dari log
ERROR_RATE=$(awk -v server="$NEW_SERVER" '
$5 ~ server && $6 >= 500 { err++ }
$5 ~ server { total++ }
END { if(total > 0) print int(err*100/total); else print 0 }
' /var/log/nginx/access.log)
echo "Error rate canary: ${ERROR_RATE}%"
if [ "$ERROR_RATE" -gt 5 ]; then
echo "ERROR RATE TINGGI! Rollback canary..."
# Tandai server sebagai down
sed -i "s/$NEW_SERVER:3000 weight=$INITIAL_WEIGHT/$NEW_SERVER:3000 down/" $CONFIG
nginx -t && nginx -s reload
echo "Rollback selesai. Alert dikirim ke tim."
exit 1
else
echo "Error rate OK. Siap untuk full rollout."
# Naikkan weight ke 50%
sed -i "s/$NEW_SERVER:3000 weight=$INITIAL_WEIGHT/$NEW_SERVER:3000 weight=50/" $CONFIG
nginx -t && nginx -s reload
fi
# GitHub Actions: deploy canary sebagai step dalam pipeline
jobs:
deploy-canary:
runs-on: ubuntu-latest
steps:
- name: Deploy canary server
run: |
ssh deploy@nginx-server \
'bash /usr/local/bin/deploy-canary.sh ${{ env.CANARY_IP }}'
- name: Monitor canary (10 menit)
run: sleep 600
- name: Promote to 100% jika sehat
run: |
ssh deploy@nginx-server \
'sed -i "s/weight=50/weight=100/g" /etc/nginx/conf.d/upstream.conf && nginx -s reload'
Pertimbangan Weight untuk Berbagai Workload #
# Workload I/O-bound (API, web server biasa)
# Distribusi berdasarkan RAM dan CPU lebih relevan
upstream io_bound {
server web-1:3000 weight=4; # 16 core, 32GB RAM
server web-2:3000 weight=2; # 8 core, 16GB RAM
server web-3:3000 weight=1; # 4 core, 8GB RAM
keepalive 32;
}
# Workload CPU-bound (image processing, ML inference, video transcoding)
# CPU core count lebih relevan dari RAM
upstream cpu_bound {
server gpu-1:8000 weight=8; # 8 GPU A100
server gpu-2:8000 weight=4; # 4 GPU A100
server cpu-1:8001 weight=1; # CPU saja, fallback
keepalive 8;
}
# Microservices dengan SLA berbeda
# Server di region terdekat mendapat weight lebih tinggi
upstream geo_aware {
# Server Asia Tenggara (dekat dengan user Indonesia)
server sg-1:3000 weight=10; # Singapore
server sg-2:3000 weight=10; # Singapore
# Server Asia Timur (latensi lebih tinggi)
server jp-1:3000 weight=3; # Japan
keepalive 16;
}
Verifikasi Distribusi Weight #
Setelah mengkonfigurasi weight, penting untuk memverifikasi bahwa distribusi traffic berjalan sesuai yang diharapkan:
# Cek distribusi traffic dari access log
# Format log harus mencakup $upstream_addr
awk '{print $5}' /var/log/nginx/access.log | \
sort | uniq -c | sort -rn
# Output contoh (weight=4, weight=2, weight=1):
# 4021 10.0.0.1:3000 ← ~57% (ekspektasi: 4/7 = 57.1%)
# 2009 10.0.0.2:3000 ← ~29% (ekspektasi: 2/7 = 28.6%)
# 978 10.0.0.3:3000 ← ~14% (ekspektasi: 1/7 = 14.3%)
# Total: 7008 request → Distribusi sangat akurat!
# Jika distribusi tidak sesuai, kemungkinan:
# 1. Server ditandai max_fails (tidak masuk rotasi sementara)
# 2. max_conns tercapai di salah satu server
# 3. Tidak menggunakan zone directive (data tidak sinkron antar worker)
# Verifikasi weight yang aktif
nginx -T | grep -A 10 "upstream app_servers"
# Atau tampilkan konfigurasi yang sedang berjalan:
nginx -T 2>/dev/null | grep -E "server.*weight"
Formula Menghitung Persentase Traffic #
Diketahui: server A weight=5, server B weight=3, server C weight=2
Total weight = 5 + 3 + 2 = 10
Persentase Server A = 5/10 × 100 = 50%
Persentase Server B = 3/10 × 100 = 30%
Persentase Server C = 2/10 × 100 = 20%
Jika traffic = 10.000 req/menit:
Server A mendapat: 5.000 req/menit
Server B mendapat: 3.000 req/menit
Server C mendapat: 2.000 req/menit
Implikasi Weight terhadap High Availability #
Satu hal yang sering diabaikan: weight mempengaruhi perilaku failover. Jika server dengan weight tinggi down, dampaknya lebih besar terhadap kapasitas keseluruhan:
Setup: Server A weight=8, Server B weight=2
Kapasitas normal: A menangani 80%, B menangani 20%
Jika Server A down:
Semua traffic masuk ke Server B
Server B yang biasa hanya menangani 20% sekarang harus menangani 100%
Server B kemungkinan besar tidak sanggup → overload!
Setup yang lebih aman untuk HA:
Server A weight=3, Server B weight=2, Server C weight=1
Total 6 bagian
Jika A down: B mendapat 2/3 = 67%, C mendapat 1/3 = 33%
→ Masih mungkin tertangani jika B dan C cukup kuat
# Konfigurasi yang mempertimbangkan kapasitas failover:
upstream production {
# Server utama: bisa menangani 100% traffic sendiri jika darurat
server 10.0.0.1:3000 weight=3 max_fails=3 fail_timeout=30s;
server 10.0.0.2:3000 weight=3 max_fails=3 fail_timeout=30s;
# Server bantu: lebih kecil, tapi bisa cover jika satu server utama down
server 10.0.0.3:3000 weight=1 max_fails=3 fail_timeout=30s;
# Backup: hanya jika semua server di atas down
server 10.0.0.4:8080 backup;
keepalive 32;
zone prod_upstream 128k;
}
# Normal: A=3/7=43%, B=3/7=43%, C=1/7=14%
# Jika A down: B=3/4=75%, C=1/4=25% (masih reasonable)
# Jika A dan B down: C=100% (overload, tapi backup server akan aktif)
Checklist Sebelum Menggunakan Weight di Production #
Sebelum menerapkan konfigurasi weight di production, pastikan semua poin berikut sudah terpenuhi:
☐ Weight sudah dihitung berdasarkan kapasitas aktual server
(CPU core, RAM, bandwidth, benchmark hasil load test)
☐ Server dengan weight paling tinggi mampu menangani setidaknya 60%
traffic sendirian (antisipasi jika server lain down)
☐ Ada setidaknya satu server backup atau konfigurasi graceful degradation
☐ Format log sudah mencakup $upstream_addr untuk memverifikasi distribusi
☐ Sudah ada monitoring aktif yang mendeteksi jika satu server menerima
traffic jauh lebih banyak dari yang diharapkan
☐ Jika ini adalah canary deployment: sudah ada script atau prosedur rollback
yang bisa dieksekusi dalam < 2 menit
☐ Konfigurasi sudah di-test di staging dengan load test yang mencerminkan
traffic production
☐ Tim sudah tahu cara mengubah weight dan reload Nginx tanpa downtime
Ringkasan #
weight=Nmengontrol proporsi traffic secara relatif — server denganweight=3mendapat 3x lebih banyak request dari server denganweight=1.- Berguna untuk server dengan kapasitas berbeda agar distribusi beban sesuai kemampuan masing-masing.
- Canary deployment: mulai dengan weight kecil untuk versi baru (misalnya
weight=5dari totalweight=100), monitor error rate, naikkan secara bertahap.- Blue-green deployment: gunakan
weight=0 backupuntuk versi standby, switch dengan ubah konfigurasi dannginx -s reload.- Bisa dikombinasikan dengan
least_conn— formula efektif =koneksi_aktif / weight, server berkapasitas besar butuh lebih banyak koneksi sebelum dianggap sibuk.- Perubahan weight bisa dilakukan tanpa downtime dengan
nginx -s reload— koneksi yang sedang berjalan tidak terputus.