✦ Day 03 • Load Balancing & Health Checks
Phase 1 • Day 03

Load Balancing & Health Checks: Ring Balancer & Circuit Breaking

เจาะลึกอัลกอริทึมการกระจายทราฟฟิก (Weighted Round-Robin & Consistent Hashing) พร้อมกลไกเฝ้าระวัง Active Probing และ Passive Circuit Breaker เพื่อสร้างระบบ High-Availability ไร้ Downtime

✦ 1. บทนำสู่ Load Balancing & Health Checks: ทำไมต้องมี Ring Balancer?

สรุปใจความสำคัญในประโยคเดียว:
Upstream Balancer & Health Checks คือ "วงแหวนกระจายงานอัตโนมัติพร้อมระบบตัดไฟ" ของ Kong ที่ทำหน้าที่กระจาย Request ไปยังเซิร์ฟเวอร์ปลายทางอย่างเป็นธรรม ตรวจจับเครื่องที่พังทันที และดึงเครื่องที่ซ่อมเสร็จกลับเข้าระบบโดยที่ลูกค้าไม่พบเจอ Error

โลกที่ไม่มี Upstream Health Checks: ภาวะ "หลุมดำของทราฟฟิก"

ลองจินตนาการว่าคุณมี Backend Pods จำนวน 4 ตัวรับผิดชอบระบบประมวลผลการชำระเงิน หากคุณใช้เพียงระบบกระจายงานภายนอก หรือชี้ Service เข้าไปที่ DNS โฮสต์เดียว เมื่อ Pod หมายเลข 3 เกิดปัญหา Out of Memory (OOM) หรือฐานข้อมูลเชื่อมต่อไม่ติด:

Kong Gateway แก้ปัญหานี้ด้วยการสร้าง In-Memory Upstream Ring Balancer โดยนำ Target ทั้งหมดมาร้อยเข้าในวงแหวนสล็อตเสมือน และวางระบบเฝ้าระวัง 2 ประตูคู่ขนาน ได้แก่ Active Probing (ส่งสัญญาณตรวจสุขภาพล่วงหน้า) ร่วมกับ Passive Circuit Breaking (ตัดไฟทันทีเมื่อลูกค้าจริงพบเจอ Error)

✦ 2. Formal Glossary & Conceptual Foundations

เพื่อความเข้าใจเชิงวิศวกรรมที่แม่นยำ ตารางด้านล่างนี้นิยามกลไกและตัวแปรหลักตาม Kong Upstream Balancing Specification:

Entity / กลไก นิยามทางการ (Formal Definition) หน้าที่หลัก (Primary Purpose) ขอบเขตและความแตกต่าง (Distinction)
Ring Balancer โครงสร้างวงแหวนเสมือน (Virtual Slots Ring) ในหน่วยความจำ OpenResty (ปกติ 10,000 slots) คำนวณและกระจาย Request ไปยัง Target ตามสัดส่วนน้ำหนัก (Weight) ทำงานในหน่วยความจำระดับ Process เร็วกว่า DNS Round-Robin ภายนอก และเปลี่ยนสถานะ Target ได้ทันทีโดยไม่ต้อง Restart
Weighted Round-Robin อัลกอริทึมกระจายโหลดแบบวนสลับลำดับถ่วงน้ำหนักตามค่า weight ของ Target จัดสรรให้เซิร์ฟเวอร์ที่มีสเปกเครื่องสูงกว่ารับสัดส่วนคำขอมากกว่า ไม่สนใจข้อมูล Session หรือ Context ของผู้ใช้ กระจายสลับรอบเป็นหลัก
Consistent Hashing อัลกอริทึมจัดสรร Request ลงบนวงแหวนแฮชโดยคำนวณจาก Key ที่กำหนด (IP, Header, Cookie) รักษา Sticky Session และดัน Cache Hit Ratio ของ Backend ให้สูงสุด Request ที่มีคีย์เหมือนกัน (เช่น User คนเดิม) จะตกไปที่ Target ตัวเดิมเสมอ เว้นแต่ Target นั้นจะล้มเหลวจึงจะ Failover ไปตัวถัดไป
Active Health Check กลไก Background Worker ที่ Kong ส่งคำขอ HTTP Probe ไปยัง http_path ของแต่ละ Target ตามรอบเวลา ตรวจสอบว่าเครื่องเป้าหมายยังมีชีวิตอยู่หรือไม่ และดึง Target ที่ฟื้นคืนชีพกลับเข้ามา Healthy มี Network Overhead จากการยิง Probe เสริม และมีความล่าช้าในการตรวจจับตามค่า interval
Passive Health Check กลไก Circuit Breaker ที่ดักสังเกตผลลัพธ์ของ Live Traffic จริงที่ส่งไปหา Target โดยไม่สร้าง Probe เสริม ตัด Target ที่พังทลายออกจาก Ring ทันทีในระดับมิลลิวินาทีเมื่อคำขอจริงของลูกค้าเริ่มเจอ HTTP 5xx หรือ Timeout ไม่สามารถดึงโหนดกลับคืนมาเป็น Healthy ได้เอง เมื่อโหนดถูกตัดแล้วจะไม่มี Live Traffic วิ่งไปอีก ต้องพึ่ง Active Probe หรือ Admin API มาช่วยฟื้นฟู
Zero-Downtime Drainage กระบวนการระบาย Connection ออกจาก Target โดยการปรับค่า weight: 0 หยุดรับ Request ใหม่ 100% แต่ยอมให้ In-flight Requests เดิมทำงานจนจบ ปลอดภัยกว่าการลบ Target ทิ้งทันที เพราะไม่ทำให้คำขอที่อยู่ระหว่างประมวลผลถูกตัดสายกลางคัน

✦ 3. Real-World Engineering War Story & Case Study

🚨 เหตุการณ์จริง: "The Rolling Deployment 502 Nightmare"
องค์กร: แพลตฟอร์มระบบจัดการบัญชีและการเงินระดับภูมิภาค (FinTech Gateway)
ความเสียหาย: คำขอตัดยอดเงินลูกค้าล้มเหลว 14,200 รายการ เกิดข้อพิพาทธุรกรรมค้างในระบบ และ SLA ตกเหลือ 94.2%

จุดเริ่มต้นของวิกฤต: ทีมงานมีระบบ Backend Service รับผิดชอบ Transaction Processing รันอยู่หลัง Kong Gateway โดยคอนฟิก Upstream ไว้แบบพื้นฐานที่สุด คือมีเฉพาะ algorithm: round-robin และไม่ได้เปิดใช้งาน healthchecks เลย เนื่องจากทีมงานคิดว่า Kubernetes Pod Readiness Probe ภายนอกทำงานได้ดีพออยู่แล้ว

วินาทีที่ระบบพังทลาย: ในคืนวันศุกร์ ทีม DevOps สั่ง Deploy อัปเดตโค้ดเวอร์ชันใหม่แบบ Rolling Update เมื่อ Pods ทยอยรับสัญญาณ SIGTERM และปิด Connection:

การกู้ภัยด้วย Kong Passive & Active Resilience: ทีมตัดสินใจเปิดใช้งาน **Passive Health Checks (Circuit Breaker)** ทันที โดยตั้งค่า http_failures: 2 และ tcp_failures: 1 พร้อมเปิด **Active Health Checks** คู่ขนานกัน
ผลลัพธ์คือ เมื่อ Pod ใดเริ่มปิดตัวหรือตอบ Connection Error แม้เพียงครั้งเดียว วงแหวนของ Kong จะ **Circuit Break** ตัด Pod นั้นออกจาก Ring ทันทีในเสี้ยววินาที และย้ายคำขอไปยัง Healthy Target ตัวอื่นอย่างไร้รอยต่อ ปรากฏการณ์ 502 Bad Gateway หายไปกลายเป็น 0% อย่างถาวร

✦ 4. Mental Model & Architecture Data Flow

อุปมาอุปไมย: "ทีมแพทย์ห้องฉุกเฉินและระบบมอนิเตอร์สัญญาณชีพ"

เปรียบเทียบการทำงานของ Kong Upstream และ Health Checks กับการจัดการทีมแพทย์ในโรงพยาบาล:

Ring Balancer & Dual Health-Check Pipeline

CLIENT REQUEST X-User-ID: 8841 GET /v1/checkout KONG IN-MEMORY UPSTREAM ENGINE RING BALANCER algorithm: consistent-hashing hash_on: header hash_on_header: X-User-ID 10,000 Slots HEALTH MONITOR Active: Probe /health interval: 2s (Recover โหนด) Passive: Circuit Breaker Failures >= 2 ➔ ตัดไฟทันที Zero-Downtime Safe ✓ TARGET 1 [HEALTHY] 10.0.1.10:8080 (Weight: 100) TARGET 2 [CIRCUIT BROKEN] 10.0.1.11:8080 (Traffic = 0%)

✦ 5. Hands-on Syntax Breakdown & Implementation (3 Levels)

Anatomy Breakdown: โครงสร้างคอนฟิก Upstream & Healthchecks Specification

_format_version: "3.0"

upstreams:
  - name: payment-pool                     # [1] ชื่อเสมือนที่ Service จะนำไปใช้เป็น host
    algorithm: round-robin                 # [2] อัลกอริทึม: round-robin หรือ consistent-hashing
    slots: 10000                           # [3] จำนวนจุดพิกัดเสมือนบนวงแหวนแฮช
    healthchecks:
      active:
        type: http
        http_path: /healthz                # [4] Path สำหรับ Background Probing
        timeout: 1                         # [5] เวลารอรับสัญญาณ Probe สูงสุด (วินาที)
        interval: 2                        # [6] ยิงทดสอบทุกๆ กี่วินาที
        healthy:
          successes: 2                     # ตอบ 200 ติดกัน 2 ครั้ง จึงจะนับว่าฟื้น
          http_statuses: [200, 204]
        unhealthy:
          http_failures: 2                 # เจอรหัส Error 2 ครั้งติดกัน ถือว่าพัง
          http_statuses: [500, 502, 503]
      passive:
        type: http                         # [7] Circuit Breaker ดักจับจากคำขอของลูกค้าจริง
        unhealthy:
          http_failures: 3                 # ลูกค้าจริงเจอ 5xx ครบ 3 ครั้ง ตัดโหนดทิ้งทันที
          http_statuses: [500, 503]

Level 1 (Beginner): Weighted Round-Robin สองโหนด

การกระจายโหลดตามสัดส่วนความสามารถของเครื่อง (เช่น เครื่องใหม่แรงกว่ารับ 80% เครื่องเก่ารับ 20%):

_format_version: "3.0"

upstreams:
  - name: order-upstream-pool
    algorithm: round-robin

targets:
  - upstream: order-upstream-pool
    target: 10.0.1.100:8080
    weight: 80     # รับ 80% ของคำขอ
  - upstream: order-upstream-pool
    target: 10.0.1.101:8080
    weight: 20     # รับ 20% ของคำขอ

services:
  - name: order-service
    host: order-upstream-pool   # ชี้ host เชิงตรรกะมาที่ชื่อ Upstream
    port: 8080
    protocol: http
    routes:
      - name: order-route
        paths:
          - /v1/orders

Level 2 (Intermediate): Consistent Hashing สำหรับ Sticky Sessions

การบังคับให้คำขอของผู้ใช้คนเดิมวิ่งไปลงที่โหนดเดิมเสมอ เพื่อให้ใช้ Local In-Memory Cache ได้เต็มประสิทธิภาพ:

_format_version: "3.0"

upstreams:
  - name: user-profile-pool
    algorithm: consistent-hashing
    hash_on: header
    hash_on_header: X-Consumer-ID          # Hash จาก Header ของลูกค้า
    hash_fallback: ip                      # หากไม่มี Header ให้ Fallback ใช้ Client IP แทน

targets:
  - upstream: user-profile-pool
    target: 10.0.2.10:8080
    weight: 100
  - upstream: user-profile-pool
    target: 10.0.2.11:8080
    weight: 100

Level 3 (Production-Grade): Full Dual Health Checks & Zero-Downtime Drain

Anti-Pattern ที่พบบ่อย: ใช้เฉพาะ Active Health Check โดยไม่เปิด Passive ทำให้ช่วงเวลาที่เครื่องดับฉับพลัน ลูกค้ายังคงหลุดไปเจอ 502 เป็นเวลาหลายวินาทีกว่าจะครบ interval

Production Solution: รวมพลัง Active Probing + Passive Circuit Breaker เข้าด้วยกัน พร้อมการทำ Zero-downtime Drain ด้วย weight: 0:

_format_version: "3.0"

upstreams:
  - name: checkout-critical-pool
    algorithm: round-robin
    healthchecks:
      active:
        type: http
        http_path: /actuator/health
        interval: 2
        timeout: 1
        healthy:
          interval: 2
          successes: 2
          http_statuses: [200]
        unhealthy:
          interval: 1
          http_failures: 2
          tcp_failures: 2
          timeouts: 3
          http_statuses: [500, 502, 503, 504]
      passive:
        type: http
        unhealthy:
          http_failures: 3
          tcp_failures: 2
          timeouts: 2
          http_statuses: [500, 502, 503, 504]

targets:
  - upstream: checkout-critical-pool
    target: 10.0.3.10:8080
    weight: 100
  - upstream: checkout-critical-pool
    target: 10.0.3.11:8080
    weight: 100
  # โหนดที่กำลังจะเตรียมซ่อมบำรุง ให้เซ็ต weight: 0 เพื่อทำ Drainage
  - upstream: checkout-critical-pool
    target: 10.0.3.12:8080
    weight: 0      # Draining Mode: ปฏิเสธคำขอใหม่ แต่ปล่อยให้คำขอเดิมทำงานจนจบ

✦ 6. Interactive Simulator: Active vs Passive Detection Latency Window

ทดลองปรับตัวแปรด้านล่าง เพื่อคำนวณเปรียบเทียบระยะเวลาที่ระบบใช้ตรวจจับโหนดที่ตาย (Detection Window) และจำนวนคำขอของลูกค้าที่จะพังเสียหาย ระหว่างการใช้ Active Health Check เพียงอย่างเดียว เทียบกับการเปิดใช้งาน Passive Circuit Breaker ร่วมด้วย:

Active Probe Interval: 2.0 วินาที
Active Failure Threshold: 2 ครั้ง
Probe HTTP Timeout: 1.0 วินาที
Live Traffic Rate (RPS): 600 req/sec
Worst-Case Active Detection Window (เวลาตรวจจับช้าสุดของ Active Probe): 4.00 วินาที
คำขอของลูกค้าที่พังเสียหายหากพึ่งพา Active Only (Pool 2 โหนด): 1,200 คำขอ
คำขอที่พังเมื่อเปิด Passive Circuit Breaker (Threshold = 3 ครั้ง): 3 คำขอ (ตัดไฟใน ~5 ms)
จำนวนคำขอของลูกค้าที่ระบบปกป้องไว้ได้สำเร็จ (Protected Requests): 1,197 คำขอ (99.75%)

✦ 7. Active Recall Deep-Dive Exam (20 ข้อ: Day 03 + Spaced Repetition)

แบบทดสอบจำนวน 20 ข้อ แบ่งเป็น: ข้อ 1-15 เจาะลึก Load Balancing & Health Checks ของ Day 03 และ ข้อ 16-20 คือ Spaced Repetition Review ดึงทบทวนแกนความรู้จาก Day 01 (Core Entities) และ Day 02 (Routing Mechanics) เพื่อตอกย้ำความจำระยะยาว

ความคืบหน้า: ตอบแล้ว 0 / 20 ข้อ
คะแนนรวม: 0 / 20