ตัดก่อนตาย เตือนก่อนบึ้ม Circuit breaker design pattern in software development
สวัสดีครับท่านผู้อ่าน วันนี้ผมจะมาพูดถึง Circuit breaker…
“Circuit breaker ที่จริงมันคือตัวตัดไฟฟ้าตัวนึง ที่ถูกออกแบบมาเพื่อป้องกันวงจรไฟฟ้า หลัก ๆ ก็คือการตัดกระแสไฟฟ้าเมื่อตรวจพบความผิดปกติในวงจร หรือ มีการไหลของกระแสไฟฟ้ามากเกินไป” อันนี้ไม่ได้ล้อเล่นนะครับ มันเป็นแบบนั้นแหละ “แต่” เดี๋ยวมันจะกลายเป็นวิชา Electric power 101 ไป…
ที่ผมจะเขียนวันนี้คือ Circuit breaker design pattern in software developmentขอบอกก่อนว่า “ตัดก่อนตาย เตือนก่อนบึ้ม ” Circuit breaker มันไม่ได้มีเอาไว้ทำให้ Service ที่ถูกเรียกไป ไม่ตายนะครับ ที่ผมกล่าวแบบนั้นคือ มันจะได้ไม่หายนะ มากไปกว่านั้นเฉย ๆ
Circuit breaker
Circuit breaker ในบทบาทของ Software development นั้นเป็น Design pattern ตัวนึงที่จะเข้ามาช่วยเราในการจัดการกับการตรวจจับ Service ของเราว่ายังคงสามารถให้บริการได้อยู่หรือไม่ ซึ่งมันจะช่วยห่อหุ้ม Service ของเรา ที่ถูกยิงเข้ามาซ้ำ ๆ ได้ด้วย แต่จะ handle บอกคน request ยังไง อันนี้ต้อง implement เองนะ…
Circuit Breaker มันสามารถใช้งานเพื่อตรวจสอบความพร้อมใช้งานของ Service ภายนอก อาจจะเป็นพวก database หรือ service อืน ๆ ที่ application ของเราเรียกได้
เมื่อ Circuit Breaker ตรวจพบว่ามีการเชื่อมต่อใดที่ fail หรือ บึ้มอยู่ มันจะทำการป้องกัน ไม่ให้ application เข้าถึง service นั้น จนกว่า ระบบจะกลับมาเป็นปกติ
ลองนึกภาพตามแบบง่าย ๆ application ของเรามีการ connect ไปหา database 10,000 ครั้ง ในระยะเวลา 1 วินาที หรือ 10,000tps ซึ่งมันทำให้ database ของเรา “FAIL” แต่ว่าเราไม่ต้องการให้เกิด Error ที่ลูกค้าเห็นว่าระบบเรา fail อยู่ เราต้องการจัดการกับข้อผิดพลาดพวกนั้นก่อน โดยไม่ต้องรอให้ connection timeout หรือ “หายนะ” จากการถูกกระหน่ำไปมากกว่านี้
Implementation
การ Implement Circuit breaker design pattern จำเป็นที่จะต้อง request อะไรบางอย่างเพื่อรักษาสถานะ ของการเชื่อมต่อเอาไว้ ซึ่งเราจำเป็นที่จะต้องทำการปิด logic บางอย่าง ของ service ที่จะถูกเรียก ก่อนการ request เพื่อที่เราจะได้เข้าถึง service นั้น ๆ ว่ายังคงอยู่ไม่
ดังนั้นเครื่องที่มีการทำงานของ Circuit breaker จำเป็นจะต้อง operate อะไรบางอย่าง เพื่อให้ service ที่จะเรียกใช้ เข้าถึงได้ โดยเราอาจจะทำได้โดยการทำ asynchronous
ในกรณีที่ Server ของเรามีหลาย node หรือ หลาย ๆ cluster เราอาจจะจำเป็นต้องเก็บข้อมูลของแต่ละ node ว่า node ไหนพร้อมใช้งาน node ไหนไม่พร้อมใช้งาน ซึ่งเราอาจจะเก็บข้อมูล ไว้ใน Redis หรือ Local cache ก็ได้ ขึ้นอยู่กับการใช้งาน ที่ทำแบบนี้ก็เพื่อที่จะให้ Service ของเราตรวจสอบก่อนว่า ที่จะทำการ request ไปนั้น service มัน available รึเปล่า
Different States of the Circuit Breaker
Circuit Breaker จะแบ่งออกเป็น 3 state
- Closed: เมื่อทุกสิ่งทุกอย่างเป็นปกติ ตัว Circuit breaker จะปิดลง และ request ต่าง ๆ จะถูกส่งไปยัง service ตาม life cycle ของมัน จนกว่ามันจะพบเจอ Fail ตัว Circuit breaker ถึงจะเปลี่ยนสถานะเป็น Open
- Open: เมื่อ Circuit breaker มี state เป็น open ระบบจะทำการ response ไปหาผู้ที่ request โดยที่จะไม่ request ไปยัง service ที่ถูก request จริง ๆ
- Half-Open: หลังจากหมดช่วงเวลา ที่กำหนดเอาไว้ Circuit breaker จะทำการ เปิดแบบครึ่งเดียว เพื่อการตรวจสอบว่าระบบที่จะถูก request ยัง fail อยู่ไหม ถ้าทดสอบแล้วยัง fail อยู่ Circuit breaker จะกลับไปเป็น state open อีกครั้ง แต่ถ้าหาก success ตัว Circuit breaker ก็จะกลับ state ไปเป็น closed
Example Implementation
เรามาลองใช้ Circuit Breaker ด้วย Netflix Hystrix แบบง่าย ๆ กันนะครับ
เริ่มต้น ผมอยากให้ทุกท่าน สร้าง rest API ง่าย ๆ ขึ้นมาก่อน 1 ตัว จะใช้ภาษาอะไรสร้างก็ได้ Node js, python, go, c# หรือ java ก็ได้ ทำให้มันรันได้บน local ของคุณ
ตัวอย่าง ผมจะใช้ Node js + express ในการทำ restful API Method GET ขึ้นมาตัวนึง ให้มัน return response json Hello World, iamgique ที่เลือก Node js เนื่องจาก มันง่ายดี
ทีนี้เรามา implement ตัว Circuit breaker กันด้วย Netflix Hystrix ผม assume ว่าทุกคนขึ้นโปรเจค Spring กันเป็นนะครับ ไม่งั้นยาว
ทำการเปิดใช้งาน Circuit Breaker
ทำการสร้าง Rest controller ขึ้นมาโดยให้ request ผ่าน API test-get
เพื่อที่จะทำการ call ไปยัง service testCall();
สร้าง Service ขึ้นมารองรับการ Call มาจาก ตัว controller ก่อนจะเข้า service จะเห็นว่ามี Annotation HystrixCommand ตัวนี้เป็น Circuit Breaker ที่จะ return กลับไปหาผู้ที่ request ว่า “Service unavailable please try again” เมื่อ service ที่จะ call ไป http://localhost:3000/test เกิดใช้งานไม่ได้
After Implement
เรามาทดสอบกันครับ ให้เราทำการรัน Service ที่ 1 ที่เราได้ทำการ Implement และ รัน Project hellocircuitbreaker แล้วลองยิง http://localhost:8080/test-get จะได้ดังภาพ
ทดลอง “ปิด” Service ตัว Service ที่ 1 ของเรา แล้วยิงใหม่อีกครั้ง
จะเห็นว่าได้ Response ที่เปลี่ยนไป จากการที่เราทำ Circuit Breaker
Conclusion
ผมว่าจริง ๆ แล้วหลาย ๆ คนก็คงอาจจะเคยใช้ Circuit breaker กันมาก่อน เพียงแต่ว่า ไม่รู้ว่าอ้อ นี่มันคือ design pattern ตัวหนึ่งเช่นกัน มันแค่ทำหน้าที่ตรวจสอบให้ จะได้ไม่หายนะมากไปกว่านี้ แล้วก็คอยไปเช็คให้ ว่ามันเลิก fail หรือยัง ถ้า success แล้วก็ให้กลับมาใช้งานได้ตามปกติ
ก็หวังว่าผู้อ่านบทความนี้ จะมีความเข้าใจใน Circuit breaker design pattern มากขึ้น และ หวังว่าจะนำไปประยุกต์ใช้กับงานของท่าน เพื่อช่วยแก้ปัญหาได้บ้าง ไม่มากก็น้อย หากผิดพลาดประการใด กระผมต้องขออภัยมา ณ จุดนี้ด้วยครับ
Ref1# Wikipedia Circuit breaker design pattern
Ref2# dzone circuit-breaker-pattern
Ref3# spring.io circuit-breaker/