ทำความรู้จัก Circuit Breaker คืออะไร? พร้อมวิธีเขียนโค้ดด้วย Go ใน 50 บรรทัด

9 นาที 19 views บันทึกเป็น PDF
ทำความรู้จัก Circuit Breaker คืออะไร? พร้อมวิธีเขียนโค้ดด้วย Go ใน 50 บรรทัด

ระบบ Microservices ล่มบ่อยใช่ไหม? มาเรียนรู้การทำ Circuit Breaker (ตัวตัดวงจรไฟฟ้าในซอฟต์แวร์) เพื่อป้องกันระบบพังต่อเนื่อง พร้อมตัวอย่างโค้ดภาษา Go เข้าใจง่าย

ทำไมระบบงานจริงต้องใช้ Circuit Breaker

เมื่อเราเริ่มสร้างระบบขนาดใหญ่ที่ประกอบด้วยหลายบริการทำงานร่วมกัน หรือที่เรียกว่า Microservices (สถาปัตยกรรมซอฟต์แวร์ที่แบ่งระบบย่อยออกเป็นบริการเล็กๆ) ปัญหาหนึ่งที่หลีกเลี่ยงไม่ได้คือความล้มเหลวของเครือข่าย เพราะการเรียกข้อมูลระหว่างกันไม่ใช่เรื่องที่แน่นอนเสมอไป บางครั้งบริการปลายทางอาจจะตอบช้า หรือบางครั้งก็อาจจะล่มไปเฉยๆ ซึ่งเป็นเหตุการณ์ปกติที่โปรแกรมเมอร์ต้องเตรียมรับมือ

ลองจินตนาการว่าคุณต้องโทรสั่งอาหารจากร้านที่คนเยอะมาก คุณโทรติดแต่ไม่มีคนรับสาย แล้วคุณก็ยังคงถือสายรออยู่อย่างนั้นโดยไม่วางสายเลย ผลคือคุณเสียเวลาและไม่ได้ทำอย่างอื่น เช่นเดียวกับบริการในระบบของคุณ ถ้าบริการ A รอคำตอบจากบริการ B ที่กำลังค้างอยู่ บริการ A ก็จะค้างตามไปด้วย สุดท้ายทรัพยากรของระบบก็จะหมดลงจนพังทั้งระบบ นี่คือเหตุผลที่เราต้องมี Circuit Breaker (ตัวตัดวงจรไฟฟ้าในซอฟต์แวร์ที่ช่วยป้องกันระบบพังต่อเนื่อง)

การเปรียบเทียบที่เห็นภาพชัดที่สุดคือสะพานไฟในบ้านเราครับ เมื่อกระแสไฟฟ้าเกินสะพานไฟจะตัดการทำงานทันทีเพื่อป้องกันไฟไหม้บ้าน ในโลกของโปรแกรมมิ่ง Circuit Breaker จะทำหน้าที่เฝ้าดูการเรียกใช้งานบริการต่างๆ หากพบว่าเกิดข้อผิดพลาดเกินกำหนด มันจะตัดการเชื่อมต่อชั่วคราว เพื่อให้ระบบส่วนอื่นยังทำงานต่อไปได้โดยไม่โดนผลกระทบจากการรอคอยที่ไร้จุดหมาย

เข้าใจสถานะทั้ง 3 ของ Circuit Breaker

เพื่อให้ Circuit Breaker ทำงานได้อย่างถูกต้อง มันจะมีสถานะหลักอยู่ 3 อย่างที่คอยควบคุมการไหลของข้อมูล สถานะแรกคือ Closed (สถานะปกติที่ยอมให้คำสั่งผ่านไปได้) ซึ่งเป็นสถานะที่เราต้องการให้ระบบอยู่เกือบตลอดเวลา เพราะหมายความว่าทุกอย่างกำลังทำงานได้ราบรื่นและไม่มีข้อผิดพลาดเกิดขึ้นเลย

สถานะที่สองคือ Open (สถานะที่หยุดการทำงานชั่วคราว) เมื่อตัวตัดวงจรพบว่าคำสั่งล้มเหลวติดต่อกันเกินจำนวนที่กำหนดไว้ มันจะเปลี่ยนเป็นสถานะนี้ทันที ในช่วงนี้ทุกคำสั่งที่พยายามเรียกใช้บริการปลายทางจะถูกปฏิเสธโดยไม่ต้องเสียเวลารอผลลัพธ์จริงๆ วิธีนี้ช่วยให้บริการปลายทางที่กำลังมีปัญหาได้พักฟื้นตัวเองโดยไม่ถูกถล่มด้วยคำสั่งใหม่ๆ เพิ่มเติม

สถานะสุดท้ายคือ Half-Open (สถานะทดสอบ) หลังจากผ่านไประยะเวลาหนึ่ง ระบบจะลองส่งคำสั่งไปตรวจสอบดูว่าบริการปลายทางหายป่วยหรือยัง ถ้าครั้งนี้ผ่านไปได้ด้วยดี มันก็จะกลับไปสู่สถานะ Closed เหมือนเดิม แต่ถ้ายังล้มเหลวอยู่ มันจะกลับไปเป็น Open ใหม่ การสลับสถานะแบบนี้ช่วยให้ระบบของเรามีความฉลาดและยืดหยุ่นในการจัดการกับปัญหาเฉพาะหน้าได้เองโดยไม่ต้องมีคนมาคอยกดปุ่มเปิดปิด

เตรียมตัวเขียนโค้ด Circuit Breaker ฉบับง่าย

ก่อนจะเริ่มเขียนโค้ด เราต้องเข้าใจก่อนว่าเรากำลังจำลองการทำงานพื้นฐานของมันขึ้นมา เราจะใช้ภาษา Go ในการเขียนตัวอย่างนี้ เพราะเป็นภาษาที่นิยมใช้ทำ Microservices สูงมาก และมีเครื่องมือจัดการเรื่องเวลา (Time) ที่แม่นยำ เหมาะแก่การทำระบบที่ต้องมีการหน่วงเวลาหรือตรวจสอบสถานะเป็นระยะๆ

ในตัวอย่างนี้เราจะสร้างโครงสร้างข้อมูลเพื่อเก็บจำนวนครั้งที่ผิดพลาด เวลาที่ล้มเหลวครั้งล่าสุด และสถานะปัจจุบันของวงจร เป้าหมายของเราคือการเขียนให้จบภายในไม่เกิน 50 บรรทัด เพื่อให้คุณเห็นว่ามันไม่ได้ซับซ้อนอย่างที่คิด การเข้าใจโครงสร้างนี้จะช่วยให้คุณนำไปปรับใช้กับภาษาอื่น เช่น JavaScript หรือ Python ได้อย่างไม่ยากเย็น

สิ่งที่คุณต้องมีคือความเข้าใจเรื่อง Mutex (ตัวล็อกข้อมูลเพื่อป้องกันการเข้าถึงพร้อมกัน) เพราะในระบบจริงจะมีหลายคำสั่งวิ่งเข้ามาพร้อมกัน ถ้าเราไม่ล็อกข้อมูลไว้ ตัวแปรสถานะของเราอาจจะเพี้ยนได้จากการที่หลายๆ ส่วนพยายามเขียนค่าลงไปพร้อมกัน การเขียนโค้ดส่วนนี้จะช่วยให้คุณเห็นภาพการทำงานระดับพื้นฐานของระบบที่รองรับการใช้งานพร้อมกันหลายคน (Concurrency)

type CircuitBreaker struct {
    state           int
    failures        int
    failureThreshold int
    lastFailureTime  time.Time
}

// 0: Closed, 1: Open, 2: Half-Open
func (cb *CircuitBreaker) Execute(req func() error) error {
    if cb.state == 1 { // ถ้าสถานะ Open ให้เช็คว่าถึงเวลาทดสอบหรือยัง
        if time.Since(cb.lastFailureTime) > 5*time.Second {
            cb.state = 2 // เปลี่ยนเป็น Half-Open
        } else {
            return errors.New("circuit is OPEN")
        }
    }
    err := req() // เรียกใช้งานจริง
    if err != nil {
        cb.failures++
        if cb.failures >= cb.failureThreshold {
            cb.state = 1 // เปลี่ยนเป็น Open
        }
        return err
    }
    cb.state = 0 // รีเซ็ตสถานะเมื่อสำเร็จ
    cb.failures = 0
    return nil
}

โค้ดส่วนนี้คือหัวใจหลัก: บรรทัดที่ 1-6 คือการสร้าง struct (โครงสร้างข้อมูล) เพื่อเก็บสถานะ บรรทัดที่ 9 คือฟังก์ชัน Execute ที่รับฟังก์ชัน req เข้ามาทำงาน บรรทัดที่ 10-16 ตรวจสอบว่าถ้าอยู่ในสถานะ Open ให้เช็คเวลา ถ้าผ่านไป 5 วินาทีให้ลองเปลี่ยนเป็น Half-Open หากไม่ถึงเวลาให้หยุดทันที บรรทัดที่ 17 คือการรันคำสั่งจริง บรรทัดที่ 18-24 ถ้าพังให้เพิ่มนับความผิดพลาด ถ้าเกินเกณฑ์ให้เปิดวงจร

ผลลัพธ์ที่ควรเห็น: เมื่อรันโค้ดชุดนี้ หากมีการเรียกใช้งานฟังก์ชันที่คืนค่า error ติดต่อกันตามจำนวนที่กำหนด ระบบจะหยุดทำงานทันทีและแสดงข้อความ "circuit is OPEN" ในการเรียกครั้งถัดไปโดยไม่เข้าไปรันโค้ดข้างในจริง ทำให้ประหยัดทรัพยากรเครื่องได้มหาศาล

ข้อควรระวังสำหรับมือใหม่

จุดที่มือใหม่มักพลาดมากที่สุดคือการตั้งค่า Threshold (เกณฑ์การตัดสินใจ) ที่เข้มงวดเกินไป หากคุณตั้งค่าให้ตัดวงจรทันทีเมื่อพลาดแค่ 1 ครั้ง ระบบของคุณอาจจะกระตุกบ่อยเกินความจำเป็นเพียงเพราะอินเทอร์เน็ตแกว่งแค่เสี้ยววินาที การตั้งค่าที่เหมาะสมต้องมาจากการสังเกตพฤติกรรมของระบบจริง

อีกเรื่องคือการจัดการกับ Fallback (การทำงานสำรอง) เมื่อวงจรถูกตัดแล้ว เราไม่ควรแค่บอกว่า "ทำไม่ได้" แต่ควรมีวิธีแก้ปัญหาให้ผู้ใช้งานด้วย เช่น ถ้าเรียกดูข้อมูลสินค้าไม่ได้ เราอาจจะแสดงข้อมูลสินค้าแนะนำที่เก็บไว้ใน Cache (หน่วยความจำชั่วคราว) แทน เพื่อให้หน้าเว็บยังดูใช้งานได้ปกติแม้ระบบหลักจะพัง

การเป็นโปรแกรมเมอร์ที่เก่งไม่ได้วัดกันที่ว่าเขียนโค้ดได้ซับซ้อนแค่ไหน แต่วัดกันที่ว่าคุณสามารถจัดการกับความล้มเหลวของระบบได้อย่างไร การทำ Circuit Breaker คือบทเรียนที่ดีในการฝึกคิดถึงกรณีเลวร้ายที่สุด (Edge case) ตั้งแต่ตอนเขียนโค้ด ซึ่งเป็นทัศนคติที่สำคัญมากสำหรับคนที่จะก้าวไปเป็นวิศวกรซอฟต์แวร์ระดับมืออาชีพ

สรุป: เริ่มต้นนำไปใช้จริง

การสร้าง Circuit Breaker ในระบบงานจริง ไม่จำเป็นต้องเขียนเองทั้งหมดเสมอไป ในโลกของการทำงานจริงจะมี Library (ชุดคำสั่งสำเร็จรูป) ที่มีประสิทธิภาพสูงให้เลือกใช้ เช่น Hystrix หรือ Resilience4j แต่การที่คุณได้ลองเขียนเองแบบ 50 บรรทัดนี้ จะทำให้คุณเข้าใจหัวใจของมันอย่างลึกซึ้ง ซึ่งหาไม่ได้จากการใช้ของสำเร็จรูปเพียงอย่างเดียว

ลองเอาโค้ดข้างต้นไปใส่ในโปรเจกต์เล็กๆ ของคุณดูครับ เช่น ลองเขียนโปรแกรมดึงข้อมูลจาก API สาธารณะที่มักจะล่มบ่อยๆ แล้วใช้ Circuit Breaker เข้าไปครอบไว้ คุณจะเห็นเลยว่าระบบของคุณดู "นิ่ง" ขึ้นมาก เพราะแทนที่จะรอให้โปรแกรมค้างหรือแสดง Error หน้าจอขาวๆ ผู้ใช้จะได้รับประสบการณ์ที่ลื่นไหลกว่าเดิม

การฝึกฝนแบบนี้จะช่วยสะสมประสบการณ์ในการทำระบบที่มั่นคง (Robust system) ซึ่งเป็นสิ่งที่บริษัทซอฟต์แวร์ต้องการตัวมากที่สุด เริ่มต้นจากการทำความเข้าใจปัญหาเล็กๆ อย่างการเรียก Network แล้วขยายไปสู่ระบบใหญ่ขึ้นเรื่อยๆ นี่แหละคือเส้นทางสู่การเป็นโปรแกรมเมอร์ที่เก่งและไว้ใจได้ในการทำงานร่วมกับทีมครับ


ที่มา: Why Your Production Microservices Should Use Circuit Breakers (And How to Implement One in 50 Lines) — DEV Community

แชร์บทความ

Facebook X LINE

บทความที่เกี่ยวข้อง

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

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

เลิกติดกับดักการดูคลิปสอน (Tutorial) แล้วมาเริ่มทำโปรเจกต์จริงกันดีกว่า เรียนรู้วิธีแก้บั๊ก การใช้ Git และการเลือกเครื่องมือให้เหมาะกับงาน เพื่อก้าวสู่การเป็นโปรแกรมเมอร์มืออาชีพ

ที่มา: DEV Community

28 minutes ago 9 นาที
2 views
เทคนิคเขียนแอป Flutter สำหรับ Meta Smart Glasses ให้ลื่นไหลและมีประสิทธิภาพ

เทคนิคเขียนแอป Flutter สำหรับ Meta Smart Glasses ให้ลื่นไหลและมีประสิทธิภาพ

เรียนรู้วิธีเขียนแอป Flutter เชื่อมต่อ Meta Smart Glasses ให้ทำงานเร็ว ไม่กระตุก ด้วยการวางสถาปัตยกรรมโค้ดและการจัดการข้อมูลแบบมือโปรที่มือใหม่ทำตามได้จริง

ที่มา: DEV Community

8 hours ago 10 นาที
5 views
เปรียบเทียบ WebSocket, SSE และ Polling เลือกวิธีทำระบบ Real-Time ให้เหมาะกับงาน

เปรียบเทียบ WebSocket, SSE และ Polling เลือกวิธีทำระบบ Real-Time ให้เหมาะกับงาน

อยากทำระบบ Real-Time แต่ไม่รู้จะเลือกใช้ Polling, SSE หรือ WebSocket ดี? มาดูวิธีเลือกใช้ให้เหมาะกับงาน เพื่อให้แอปของคุณทำงานลื่นไหลและประหยัดทรัพยากรเซิร์ฟเวอร์

ที่มา: DEV Community

11 hours ago 10 นาที
5 views