12/04/2026 18:16น.

Golang The Series EP 129: High Availability & Failover – ออกแบบระบบให้ "อึด ถึก ทน"
#High Availability
#Go
#Golang
#Failover
ยินดีต้อนรับชาว Gopher ทุกท่านครับ! เคยสงสัยไหมว่าทำไมแอปพลิเคชันระดับโลกอย่าง Facebook หรือ Netflix ถึงแทบไม่เคยล่มเลย? หรือต่อให้เกิดเหตุการณ์ระบบขัดข้อง เขาก็ยังประคองตัวให้ใช้งานได้ต่อราวกับไม่มีอะไรเกิดขึ้น?
คำตอบไม่ใช่ "การเขียนโค้ดให้ไม่มีบั๊ก" (เพราะในโลกวิศวกรรมซอฟต์แวร์ No Bug is a Myth) แต่คำตอบที่แท้จริงคือการออกแบบสถาปัตยกรรมให้มี High Availability (HA) หรือความพร้อมใช้งานสูงนั่นเองครับ
1. High Availability (HA) และมนต์ขลังของเลข "9"
ในวงการ SRE (Site Reliability Engineering) เราวัดความอึดของระบบด้วย "The Nines" หรือจำนวนเลข 9 ของเปอร์เซ็นต์ Uptime ยิ่งเลข 9 เยอะ ระบบยิ่งต้องเทพ:
การจะไปให้ถึง 99.99% ได้ เราต้องกำจัด SPOF (Single Point of Failure) หรือ "จุดตายเดี่ยว" ออกไปให้หมด กฎเหล็กคือ: ทุกองค์ประกอบของระบบต้องมีอย่างน้อยสอง (Redundancy) และต้องอยู่คนละที่กันเสมอ
2. กลยุทธ์ Redundancy: การมี "ตัวสำรอง" ที่ชาญฉลาด
เราแบ่งกลยุทธ์การสำรองระบบออกเป็น 2 รูปแบบหลัก:
- Active-Active: รัน Server หลายตัวพร้อมกัน และใช้ Load Balancer กระจาย Request ไปทุกตัว ข้อดีคือช่วยขยายขีดความสามารถ (Scaling) และถ้าตัวหนึ่งพัง ตัวที่เหลือก็รับงานต่อได้ทันที
- Pro Tip: การเลือก Algorithm ของ Load Balancer เช่น Round Robin (วนไปทีละเครื่อง) หรือ Least Connections (ส่งไปเครื่องที่งานน้อยที่สุด) มีผลอย่างมากต่อเสถียรภาพของระบบภายใต้ Load หนักๆ
- Active-Passive (Failover): มีเครื่องหลัก (Primary) ทำงาน และมีเครื่องสำรอง (Standby) รอนิ่งๆ เมื่อเครื่องหลักตาย ระบบตรวจสอบจะดีดตัวสำรองขึ้นมาทำงานแทน มักใช้ในระบบที่ยากต่อการรันพร้อมกัน เช่น ระบบจัดการไฟล์หรือ Database บางประเภท
3. Failover Design ในระดับ Database: เมื่อข้อมูลคือหัวใจ
Server พังเราปั้นใหม่ได้ในวินาทีด้วย Container แต่ถ้า Database พัง ข้อมูลสูญหายคือหายนะ เราจึงต้องมี:
- Replication: การทำสำเนาข้อมูลจาก Leader ไปยัง Follower แบบ Real-time
- Read Replicas: แยกเครื่องสำหรับ "อ่าน" ออกมาเพื่อลดภาระเครื่องหลัก และหาก Leader พัง เราสามารถ Promote หนึ่งใน Follower ขึ้นมาเป็น Leader ตัวใหม่ได้ (Leader Election)
- Quorum Awareness: ในระบบ Distributed ขั้นสูง เรามักใช้จำนวนเครื่องเลขคี่ (เช่น 3, 5 ตัว) เพื่อให้ระบบทำการ "โหวต" เลือกเครื่องหลักใหม่ได้โดยไม่เกิดปัญหา Split-brain (อาการที่ต่างคนต่างคิดว่าตัวเองเป็นหัวหน้าจนข้อมูลขัดแย้งกัน)
4. Implementation ใน Go: หัวใจของ Cloud-Native App
ในฐานะ Go Developer เราต้องเตรียมแอปให้พร้อมสำหรับ HA ผ่าน 2 กลไกสำคัญที่ห้ามมองข้าม:
A. Advanced Health Checks (/livez & /readyz)
ในมาตรฐานการจัดการ Container (เช่น Kubernetes) เราแยก Health Check เป็น 2 ประเภท:
- Liveness (/livez): เช็คว่าแอปยัง "มีชีวิต" ไหม? ถ้าพัง (เช่น Deadlock) ให้ Restart เครื่องนี้ซะ
- Readiness (/readyz): เช็คว่าแอป "พร้อมรับงาน" ไหม? เช่น ต่อ Database ติดหรือยัง? ถ้าไม่พร้อม ให้ Load Balancer หยุดส่ง Request มาที่นี่ชั่วคราว
Go
func main() {
http.HandleFunc("/readyz", func(w http.ResponseWriter, r *http.Request) {
// ตรวจสอบ Dependency เช่น DB, Redis
if err := checkDependencies(); err != nil {
w.WriteHeader(http.StatusServiceUnavailable) // 503
return
}
w.WriteHeader(http.StatusOK) // 200
w.Write([]byte("Ready"))
})
log.Fatal(http.ListenAndServe(":8080", nil))
}
B. Robust Graceful Shutdown
ห้ามปล่อยให้ Request ของ User "ค้าง" หรือ "พัง" เมื่อเราสั่งปิด Server เพื่ออัปเดตเวอร์ชัน เราต้องรอให้งานที่ค้างอยู่เสร็จสิ้นก่อนปิดตัวลง
Go
package main
import (
"context"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
)
func main() {
server := &http.Server{Addr: ":8080"}
// ดักจับ Signal จาก OS (เช่น SIGTERM จาก Kubernetes)
stop := make(chan os.Signal, 1)
signal.Notify(stop, os.Interrupt, syscall.SIGTERM)
go func() {
if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatalf("Listen error: %v", err)
}
}()
<-stop // รอรับสัญญาณปิดเครื่อง
log.Println("Shutting down server...")
// ให้เวลาเคลียร์งานที่ค้างอยู่ 30 วินาที (Timeout)
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()
if err := server.Shutdown(ctx); err != nil {
log.Fatalf("Server forced to shutdown: %v", err)
}
log.Println("Server gracefully stopped")
}
5. Multi-Region: เมื่อโลกทั้งใบคือ Data Center
ระบบ HA ขั้นสุดยอดต้องวางแผนรับมือกับภัยพิบัติ (Disaster Recovery) โดยการกระจาย Server ไว้คนละ Availability Zone (AZ) หรือคนละ Region (เช่น สิงคโปร์ และ ญี่ปุ่น) เพื่อให้มั่นใจว่าต่อให้ทั้งภูมิภาคไฟดับ เว็บของคุณจะยังคงออนไลน์อยู่เสมอจากอีกซีกโลกหนึ่ง
สรุป
การออกแบบ High Availability & Failover ไม่ใช่แค่เรื่องของการจ่ายเงินซื้อ Cloud แพงๆ แต่มันคือ Mindset ของวิศวกรซอฟต์แวร์ที่มองว่า "ทุกอย่างมีวันพัง" หน้าที่ของเราคือสร้างระบบที่ล้มแล้วลุกไว (Resilience) และโปร่งใสต่อผู้ใช้งานมากที่สุดครับ
ในตอนหน้า (EP 130): เราจะนำแนวคิดเรื่อง HA มาประยุกต์ใช้กับโจทย์ที่ปราบเซียนที่สุดอย่าง Scalable Real-time WebSocket โดยใช้ Redis Pub/Sub เพื่อให้ระบบแชทขยายเครื่องได้ไม่จำกัด! ห้ามพลาดครับ