12/04/2026 18:16น.

EP.123 Load Balancing & Sticky Sessions สำหรับ WebSocket (Production-Ready Guide)
#WebSocket Server
#Go
#Kubernetes
#Real-time System
#Golang
เมื่อ WebSocket Server ของคุณเริ่มมีผู้ใช้งานจำนวนมา การเพิ่ม Server หรือ Pod อย่างเดียว ไม่เพียงพอ
ปัญหาที่มักเกิดขึ้นในระบบจริง ได้แก่
- ผู้ใช้เชื่อมต่อแล้วหลุดกลางทาง
- Message ส่งไม่ถึงหรือมาช้า
- Client reconnect วนจนระบบ overload
สาเหตุหลักแทบทุกครั้งมาจาก 👉 Load Balancer ที่ไม่เข้าใจ WebSocket และไม่มี Sticky Session
บทความนี้จะพาคุณเข้าใจตั้งแต่ แนวคิดพื้นฐาน → วิธีใช้งานจริง → Best Practices ระดับ Production
🎯 เป้าหมายของบทความนี้
หลังอ่านจบ คุณจะเข้าใจว่า
- ทำไม WebSocket ต้องใช้ Sticky Session
- Load Balancer แบบไหนรองรับ WebSocket ได้จริง
- วิธี Scale ระบบโดยไม่ทำให้ผู้ใช้หลุด
- แนวคิดออกแบบ WebSocket Server ให้พร้อม Production
🧠 ทำไม WebSocket “ไม่เหมือน” HTTP
HTTP (Stateless)
- Request → Response → จบ
- Load Balancer กระจาย request ได้อิสระ
- เปลี่ยน Server ทุกครั้งไม่กระทบผู้ใช้
WebSocket (Stateful)
- Connect ครั้งเดียว → ค้างยาว
- Connection ผูกกับ Server ตัวเดียว
- ถ้า request ถูกส่งไป Server อื่น → ❌ connection หลุดทันที
🔑 WebSocket ต้องอยู่กับ Server เดิมตลอดอายุการเชื่อมต่อ
🍪 Sticky Session คืออะไร?
Sticky Session คือการบอก Load Balancer ว่า
“Client คนนี้ ต้องถูกส่งไป Server ตัวเดิมเสมอ”
วิธีทำ Sticky Session ที่ใช้กันจริง
- Cookie-based
- IP Hash
- Header-based
👉 สำหรับ WebSocket: ต้องมี Sticky Session เสมอ
❌ จะเกิดอะไรถ้า “ไม่มี” Sticky Session
สถานการณ์จริงที่พบบ่อย
- Client เชื่อมต่อ WebSocket ผ่าน Load Balancer
- LB ส่งไป Pod A
- ระบบ Scale เพิ่ม Pod B
- Packet ถัดไปถูกส่งไป Pod B
- ❌ WebSocket connection พังทันที
ผลลัพธ์ที่ผู้ใช้เห็นคือ
- หลุดเอง
- Reconnect วน
- Message หาย
⚖️ ประเภท Load Balancer ที่ใช้งานกับ WebSocket ได้จริง
1. Layer 4 Load Balancer (TCP)
เหมาะกับ WebSocket มากที่สุด
ตัวอย่าง
- AWS NLB
- GCP TCP Load Balancer
- HAProxy (TCP mode)
ข้อดี
- ไม่แตะ protocol
- Connection คงที่
- Sticky โดยธรรมชาติ
2. Layer 7 Load Balancer (HTTP)
ใช้ได้ แต่ต้องตั้งค่าให้ถูก
ตัวอย่าง
- Nginx
- AWS ALB
- Traefik
สิ่งที่ต้องมี
- รองรับ
Upgrade: websocket - เปิด Sticky Session
- Timeout ต้องยาวพอ (ไม่ต่ำกว่า 1–2 ชั่วโมง)
⚙️ ตัวอย่าง Sticky Session (Nginx)
upstream websocket_backend {
ip_hash;
server ws1:8080;
server ws2:8080;
}
server {
location /ws {
proxy_pass http://websocket_backend;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_read_timeout 1h;
}
}
ip_hash คือ Sticky Session แบบง่าย ใช้ได้ดีในหลายกรณี
📦 Sticky Session บน Kubernetes
แนวทางที่ใช้จริง
1. Service + Session Affinity
spec:
sessionAffinity: ClientIP
2. Ingress (Nginx Ingress)
nginx.ingress.kubernetes.io/affinity: "cookie"
nginx.ingress.kubernetes.io/session-cookie-name: "ws-session"
🔧 ตัวอย่าง WebSocket Server ด้วย Go (Production-friendly)
package main
import (
"log"
"net/http"
"github.com/gorilla/websocket"
)
var upgrader = websocket.Upgrader{
CheckOrigin: func(r *http.Request) bool {
return true
},
}
func wsHandler(w http.ResponseWriter, r *http.Request) {
conn, err := upgrader.Upgrade(w, r, nil)
if err != nil {
log.Println("upgrade error:", err)
return
}
defer conn.Close()
for {
msgType, msg, err := conn.ReadMessage()
if err != nil {
log.Println("read error:", err)
break
}
err = conn.WriteMessage(msgType, msg)
if err != nil {
log.Println("write error:", err)
break
}
}
}
func main() {
http.HandleFunc("/ws", wsHandler)
log.Println("WebSocket server started on :8080")
http.ListenAndServe(":8080", nil)
}
⚠️ สำคัญ
เมื่อมี Load Balancer ด้านหน้า → ต้องมี Sticky Session
ไม่เช่นนั้น connection นี้จะไม่ถูกส่งกลับมาที่ Server เดิม
📈 การ Scale โดยไม่ทำให้ Connection หลุด
❌ สิ่งที่ไม่ควรทำ
- Kill Pod ทันที
- Rolling Update แบบไม่สนใจ connection
✅ วิธีที่ถูกต้อง
- Mark Pod เป็น draining
- ไม่รับ connection ใหม่
- รอ client disconnect
- ค่อย terminate Pod
🧠 แนวคิดสำคัญ: Stateless WebSocket Server
เพื่อให้ Scale ได้จริง
- อย่าเก็บ state ไว้ใน memory อย่างเดียว
- ใช้ Redis / External Store
- Client reconnect แล้ว recover ได้
🔁 รองรับ Reconnect อย่างปลอดภัย
สิ่งที่ระบบ Production ควรมี
- Reconnect logic ฝั่ง client
- Resume session
- Token-based authentication
- Idempotent message
🧪 สิ่งที่ต้องทดสอบก่อนขึ้น Production
- Scale Pod ระหว่างมี user เชื่อมต่อ
- Reconnect พร้อมกันจำนวนมาก
- Chaos Test (สุ่มปิด Pod)
- ตรวจสอบ message loss และ duplication
🚀 ท้าให้ลอง!
ลองทำตามนี้
- เปิด Sticky Session บน Load Balancer
- Scale WebSocket Server ระหว่างใช้งานจริง
- สังเกตว่า user หลุดหรือไม่
- ปรับ timeout และ draining ให้เหมาะสม
ถ้าผู้ใช้ไม่รู้สึกอะไรเลย
แปลว่า ระบบคุณผ่านระดับ Production แล้วจริง ๆ ✅
🔮 EP ถัดไป EP.124 Security & Authentication ขั้นสูงสำหรับ WebSocket
ในตอนถัดไป เราจะเจาะลึก
- JWT & Token Strategy
- ป้องกัน WebSocket Hijacking
- Secure Handshake ระดับ Enterprise