☕ 5-Min Tech Story #24

Retry Storm: เมื่อความพยายามอันแสนดี กลายเป็นปืนกล DDoS ถล่มระบบตัวเองจนพังยับ

⏱️ ใช้เวลาอ่านประมาณ: 4 นาที 20 วินาที

ในคู่มือ Resilience 101 กฎพื้นฐานสอนไว้ว่า: "ถ้าเรียก Service ปลายทางแล้วล้มเหลว จงเขียนกลไก Retry ซ้ำสัก 3 รอบ เพื่อป้องกันปัญหาเน็ตสะดุดชั่วคราว"

ฟังดูมีเหตุผลและปลอดภัย... แต่ทำไมในคืนที่ฐานข้อมูลแค่สะอึกไป 3 วินาที ระบบ Retry ที่แสนหวังดีนี้ กลับขยายจำนวน Request พุ่งพรวดขึ้น 10 เท่าตัวในพริบตาเดียว จนเหมือนบริษัทกำลังโดนแฮกเกอร์ยิง DDoS Attack จากฝีมือโค้ดของตัวเอง?

💥 ปรากฏการณ์ทวีคูณลูกโซ่ (Cascading Retry)

สมมติว่าคุณมี Microservices ร้อยเรียงกัน 3 ชั้น: Gateway ➔ Order Service ➔ Payment Service

นักพัฒนาแต่ละทีมต่างคนต่างใส่ logic: "ถ้าปลายทางพัง กู Retry 3 ครั้ง":

จากคำสั่งซื้อแค่ 1 ครั้งของลูกค้า กลายพันธุ์เป็น 3 × 3 = 9 Requests ที่ยิงอัดกระหน่ำใส่ Payment Service ตัวเดิมที่กำลังขาดอากาศหายใจอยู่แล้ว!

"เปรียบเหมือนคนกำลังจมน้ำแทนที่จะโยนห่วงยางไปช่วย เรากลับส่งฝูงชนอีก 50 คนกระโดดลงไปเกาะคอเขาพร้อมกันเพื่อถามว่า 'ไหวไหมๆๆ' ซ้ำๆ!"

🥁 จังหวะกลองนรก: การ Retry พร้อมเพรียงกัน (Thundering Retry)

ถ้าการ Retry ตั้งเวลาแบบทื่อๆ เช่น "รอ 1 วินาทีแล้วลองใหม่"

เมื่อคำขอ 2,000 อันพังพร้อมกันในวินาทีที่ 0... ทั้ง 2,000 อันก็จะ พร้อมใจกันกระหน่ำยิงซ้ำลงมาในวินาทีที่ 1 พร้อมกันเป๊ะ เกิดเป็นคลื่นสึนามิกระแทกเป็นจังหวะๆ จนเซิร์ฟเวอร์ปลายทางไม่มีวันเงยหน้าขึ้นมาฟื้นตัวได้เลยตลอดกาล

🛡️ 3 คาถาดับพายุ: Backoff, Jitter และ Circuit Breaker

1. Exponential Backoff + Jitter (ทิ้งช่วงและสุ่มเวลา)

อย่า Retry ทันที และอย่ารอเวลาเท่ากันเป๊ะ ให้เพิ่มระยะเวลารอแบบทวีคูณ (1s, 2s, 4s) พร้อมกับ บวกเวลาสุ่ม (Jitter) เข้าไปด้วยเสมอ:

// เวลารอ = (2 ^ retryCount) + สุ่มเวลาเล็กน้อย
val delay = baseDelay * 2.0.pow(attempt) + Random.nextDouble(0.1, 0.5)

คลื่น Request ที่เคยกรูเข้าพร้อมกัน จะแตกกระจายแถวออกไปคนละเสี้ยววินาที ทำให้แรงปะทะลดลงมหาศาล

2. ติดเบรกเกอร์ตัดไฟ (Circuit Breaker)

ใช้เครื่องมืออย่าง Resilience4j มาตรวจจับ ถ้าอัตราความล้มเหลวของปลายทางทะลุ 50% ให้สับคัตเอาต์เปิดวงจร (OPEN) ทันที เพื่อ ปฏิเสธคำขอทันทีโดยไม่ต้องเสียเวลายิงไปรบกวนปลายทาง เปิดโอกาสให้เซิร์ฟเวอร์หลังบ้านได้เคลียร์งานและกู้ระบบขึ้นมาใหม่อย่างสงบ

💡 5-Min Takeaway

"ในระบบ Distributed System ความตื๊อไม่ใช่สิ่งที่ดีเสมอไป" เมื่อระบบปลายทางเกิดปัญหา การทู่ซี้พยายามส่งซ้ำแบบไม่ลืมหูลืมตาคือการเร่งปฏิกิริยาให้ระบบล่มเร็วขึ้น การใส่ Exponential Backoff ผสม Jitter และการกล้าตัดใจสับ Circuit Breaker เพื่อปล่อยให้ระบบได้พักฟื้น คือเส้นแบ่งระหว่างระบบที่ฟื้นตัวได้เอง กับระบบที่ต้องปลุกทีมมาช่วยกันรีสตาร์ตตอนตีสาม