Alerting คืออะไรและทำไมมือใหม่ต้องใส่ใจ
ในการทำงานสายโปรแกรมเมอร์ เมื่อเราสร้างระบบขึ้นมาแล้ว สิ่งที่สำคัญพอๆ กับการเขียนโค้ดคือ Alerting (ระบบแจ้งเตือนเมื่อระบบมีปัญหา) ลองจินตนาการว่าคุณเป็นเจ้าของร้านอาหารที่มีกริ่งเตือนเมื่ออาหารในครัวทำเสร็จ ถ้ากริ่งดังตลอดเวลาทั้งที่อาหารยังไม่เสร็จ หรือกริ่งไม่ดังเลยแม้ไฟจะไหม้ครัว คุณย่อมบริหารจัดการร้านไม่ได้ การทำระบบแจ้งเตือนก็เช่นกัน มันคือการตั้งค่าให้เซนเซอร์คอยตรวจสอบสถานะของซอฟต์แวร์และส่งสัญญาณเตือนมาให้เราทันทีที่เกิดความผิดปกติ
Alerting ไม่ใช่แค่การตั้งค่าให้ระบบส่งอีเมลหาเราเมื่อเครื่องพัง แต่มันคือศาสตร์ของการวัดผลที่แม่นยำ หลายคนเริ่มต้นด้วยการตั้งค่าแบบง่ายๆ เช่น "ถ้าคนเข้าเว็บน้อยกว่า 10 คน ให้เตือน" ซึ่งในความเป็นจริงมันอาจเป็นเพราะช่วงเวลานั้นเป็นเวลาตี 3 ที่ไม่มีใครเล่นอยู่แล้ว การตั้งค่าที่ไม่ละเอียดพอจะทำให้คุณได้รับข้อความแจ้งเตือนที่ไร้ประโยชน์จนเกิดอาการ "Alert Fatigue" หรือการชินชากับการแจ้งเตือนจนไม่สนใจมันอีกต่อไป
การเข้าใจว่า Monitoring (กระบวนการเฝ้าสังเกตระบบ) ทำงานอย่างไรจะช่วยให้คุณนอนหลับได้อย่างสนิทใจ การตั้งค่าแจ้งเตือนคือการสะท้อน "เจตจำนง" ของคุณลงไปในโค้ด หากคุณตั้งค่าไม่ดี ระบบจะแจ้งเตือนคุณด้วยสิ่งที่คุณ "เขียน" ไม่ใช่สิ่งที่คุณ "คิด" ดังนั้นจงจำไว้ว่าการทำระบบแจ้งเตือนคือเกมแห่งรายละเอียดที่ต้องใช้ความรอบคอบสูงมาก
บทเรียนที่ 1: อย่าใช้ Throughput เป็นตัวตั้งค่าหลัก
มือใหม่มักจะเผลอใช้ Throughput (ปริมาณงานที่ระบบทำได้ต่อหน่วยเวลา) มาเป็นเกณฑ์หลักในการแจ้งเตือน เช่น การนับจำนวนข้อความที่ประมวลผลได้ใน 1 นาที หากตัวเลขต่ำกว่าที่กำหนดให้แจ้งเตือนทันที วิธีนี้ดูเหมือนจะสมเหตุสมผล แต่ในทางปฏิบัติมันมักจะล้มเหลวเพราะงานแต่ละชิ้นไม่ได้มีขนาดเท่ากันเสมอไป เช่น ข้อความหนึ่งฉบับอาจบรรจุข้อมูล 10 รายการ ซึ่งถ้าเรานับแค่จำนวนข้อความ เราจะมองข้ามความจริงที่ว่างานที่แท้จริงอาจจะค้างอยู่มหาศาล
การใช้ค่าเฉลี่ยของจำนวนงานที่ทำได้ต่อนาทีนั้นมักจะสร้างปัญหา "แจ้งเตือนปลอม" ในช่วงที่ระบบไม่มีงานเข้าจริงๆ ในทางกลับกัน การวัดค่า Age of Oldest Message (อายุของข้อความที่เก่าแก่ที่สุดในคิว) จะให้ผลลัพธ์ที่แม่นยำกว่ามาก เพราะถ้าคิวงานว่างเปล่า ระบบก็จะไม่แจ้งเตือน แต่ถ้ามีงานค้างและไม่ถูกจัดการ อายุของข้อความนั้นจะเพิ่มขึ้นเรื่อยๆ จนถึงเกณฑ์ที่เรากำหนด ทำให้เราแยกออกได้ชัดเจนว่าระบบ "ว่างงาน" หรือ "มีปัญหาจนงานค้าง"
ลองเปรียบเทียบระหว่างการตั้งค่าแบบเดิมกับการใช้เวลาของข้อความเก่าที่สุด:
// แบบที่ผิด: เช็คจำนวนงานต่อนาที (อาจแจ้งเตือนผิดพลาดตอนระบบว่าง)
if (throughput < 10) { triggerAlert(); }
// แบบที่ถูก: เช็คว่างานเก่าสุดค้างนานเกิน 1 ชั่วโมงหรือไม่
if (oldestMessageAge > 3600) { triggerAlert(); }
โค้ดตัวอย่างด้านบนแสดงให้เห็นว่าการวัดอายุงานที่เก่าที่สุด (วินาที) ช่วยให้เรากำหนดเงื่อนไขที่ชัดเจนได้มากกว่าการเดาจำนวนงานต่อนาที ทำให้เรามีหลักฐานที่แน่นหนาเวลาต้องอธิบายว่าทำไมระบบถึงส่งสัญญาณเตือน
บทเรียนที่ 2: การวัดผลที่หางแถว (Catching the Tail)
เมื่อระบบเริ่มทำงานช้าลง เรามักจะอยากรู้ว่าเกิดจากอะไร Tail Latency (ความหน่วงของงานส่วนน้อยที่ใช้เวลานานผิดปกติ) คือตัวบอกเหตุการณ์ที่สำคัญ หากคุณพบว่ามีงานเพียงไม่กี่ชิ้นที่ใช้เวลานานกว่าปกติมาก คุณไม่ควรเหมาเข่งว่าทั้งระบบกำลังพัง แต่ควรเจาะจงไปที่งานชิ้นนั้นๆ หากคุณตั้งค่าแจ้งเตือนแบบกว้างๆ คุณจะได้รับข้อความแจ้งเตือนที่ไม่มีประโยชน์และไม่รู้จะไปแก้ไขที่จุดไหน
Deadline หรือการกำหนดเวลาสูงสุดที่งานหนึ่งชิ้นควรจะเสร็จ เป็นเครื่องมือที่ทรงพลังมาก แทนที่จะดูค่าเฉลี่ยความเร็วรวม คุณควรตั้งค่าแจ้งเตือนเมื่อมีงานชิ้นใดชิ้นหนึ่งเกินเวลาที่กำหนด (เช่น 30 วินาที) หากการแจ้งเตือนนี้ดังขึ้นเพียงครั้งเดียวหรือสองครั้ง นั่นหมายถึง "งานชิ้นนั้นอาจจะใหญ่เกินไป" แต่ถ้ามันดังรัวๆ แสดงว่า "ระบบทั้งระบบกำลังติดขัด" ซึ่งเป็นการแยกแยะปัญหาที่เฉียบคมมาก
เมื่อต้องจัดการกับคำขอ (Request) ที่ช้า ให้ลองใช้ตัวอย่างเปรียบเทียบนี้ในการตัดสินใจ:
- ถ้ามีงานช้า 10 ชิ้นจาก 10,000 ชิ้น: ไม่ใช่อาการโคม่าของระบบ แต่เป็นแค่ไฟล์บางไฟล์ที่ใหญ่เกินไป
- ถ้ามีงานช้า 100 ชิ้นจาก 1,000 ชิ้น: นี่คืออาการระบบล่มหรือติดขัดในวงกว้าง ต้องรีบแก้ไข
การแยกแยะระหว่าง "งานช้าชั่วคราว" กับ "ระบบล่ม" จะช่วยให้คุณไม่ตื่นตระหนกจนเกินเหตุ และสามารถจัดลำดับความสำคัญในการแก้ไขปัญหาได้ถูกต้องตามความเป็นจริง
บทเรียนที่ 3: ระวังการตั้งค่า Threshold ที่ไม่มีที่มา
มือใหม่มักจะตั้งค่า Threshold (ขีดจำกัดที่กำหนดไว้) ตามความรู้สึก เช่น "คิดว่า 50 น่าจะโอเค" หรือ "เห็นคนอื่นตั้ง 100 ก็ตั้งตาม" การตั้งค่าแบบนี้คือหายนะที่รอวันปะทุ เพราะเมื่อเกิดเหตุการณ์ 3 AM ที่ระบบแจ้งเตือนขึ้นมา คุณจะไม่มีวันรู้เลยว่าทำไมตัวเลขนี้ถึงสำคัญ หรือควรปรับมันเป็นเท่าไหร่ถึงจะเหมาะสมกับสถานการณ์จริง
การตั้งค่าที่ดีต้องมีที่มาที่ไปเสมอ เช่น อ้างอิงจาก SLO (Service Level Objective หรือเป้าหมายระดับการให้บริการ) หรืออ้างอิงจากเวลาที่ลูกค้าเริ่มรู้สึกว่าเว็บช้า หากคุณไม่สามารถอธิบายได้ว่าเลข 50 หรือ 100 มาจากไหน คุณควรเริ่มจากการเก็บข้อมูล (Log) ไว้ก่อนสักระยะ เพื่อดูพฤติกรรมปกติของระบบ แล้วค่อยนำค่าที่ได้มาคำนวณเป็นเกณฑ์แจ้งเตือนที่สมเหตุสมผล
จุดที่มือใหม่มักพลาดคือการเปลี่ยน Threshold ไปเรื่อยๆ เมื่อได้รับแจ้งเตือนรำคาญ (False Positive) จนกลายเป็นว่าค่าที่ตั้งไว้ไม่ได้สะท้อนความจริงอีกต่อไป:
// ตัวอย่างการตั้งค่าที่ควรอ้างอิงจากข้อมูลจริง
const MAX_ALLOWED_LATENCY_MS = 3000; // อ้างอิงจากความเร็วที่ผู้ใช้ยังรับได้
if (requestTime > MAX_ALLOWED_LATENCY_MS) {
// บันทึก Log เพื่อนำไปวิเคราะห์ต่อ
logError('Request took too long', { time: requestTime });
}
การใส่คอมเมนต์หรือเหตุผลกำกับไว้ในโค้ด (เช่น อ้างอิงว่าทำไมถึงเลือก 3000ms) จะช่วยให้คุณหรือเพื่อนร่วมทีมเข้าใจเจตจำนงของระบบในอนาคต และสามารถปรับเปลี่ยนได้อย่างมั่นใจเมื่อระบบเติบโตขึ้น
บทเรียนที่ 4: ทุกข้อมูลต้องผ่านการกลั่นกรองบริบท
คุณต้องเข้าใจว่าข้อมูลที่คุณได้รับผ่านการแจ้งเตือนนั้นเป็นเพียง "ตัวแทน" ของปัญหา ไม่ใช่ตัวปัญหาเอง การที่คุณเห็นตัวเลขใน Dashboard (หน้าจอแสดงผลข้อมูล) พุ่งสูงขึ้น ไม่ได้หมายความว่าคุณรู้สาเหตุที่แท้จริงเสมอไป บ่อยครั้งที่ข้อมูลเหล่านั้นถูกบิดเบือนจากโครงสร้างของระบบ เช่น การนับจำนวน HTTP Request ที่อาจรวมเอาการโหลดรูปภาพเล็กๆ น้อยๆ เข้าไปด้วย ทำให้ตัวเลขดูสูงเกินจริง
Context (บริบท) ของข้อมูลเป็นเรื่องสำคัญมาก การเรียนรู้ที่จะ "อ่าน" ข้อมูลให้ทะลุถึงสิ่งที่เกิดขึ้นจริงคือทักษะที่โปรแกรมเมอร์เก่งๆ มี คุณต้องถามตัวเองเสมอว่า "ตัวเลขนี้กำลังบอกอะไรเกี่ยวกับสิ่งที่ผู้ใช้ได้รับจริงๆ?" หากข้อมูลในระบบแจ้งเตือนไม่สัมพันธ์กับประสบการณ์ของผู้ใช้ คุณต้องกลับมาปรับปรุงวิธีการเก็บข้อมูลหรือวิธีการนับใหม่ทันที
ตัวอย่างสถานการณ์ที่คุณควรตั้งคำถามกับข้อมูล:
- ระบบแจ้งว่า CPU สูงขึ้น: มันสูงเพราะงานเพิ่มขึ้นจริง หรือเพราะมีโค้ดที่วนลูปไม่รู้จบ?
- ฐานข้อมูลทำงานช้า: มันช้าเพราะคนใช้งานเยอะ หรือเพราะเราลืมทำ Indexing (การทำดัชนีข้อมูลเพื่อให้ค้นหาเร็วขึ้น)?
- การแจ้งเตือนดังตอนตี 3: มันเป็นปัญหาเร่งด่วนที่ต้องตื่นมาแก้ หรือเป็นแค่การทำงานตามรอบปกติที่ตั้งค่าไว้ผิดพลาด?
สรุป: เปลี่ยนความรู้ให้เป็นการแจ้งเตือนที่ชาญฉลาด
การทำระบบแจ้งเตือนไม่ใช่แค่การเขียนโค้ดเพื่อเช็คค่า แต่คือการสร้าง Observability (ความสามารถในการมองเห็นและเข้าใจสถานะภายในของระบบ) ที่ดีให้กับงานของคุณ จำไว้ว่าเป้าหมายสูงสุดคือการได้รับแจ้งเตือนเฉพาะตอนที่ระบบมีปัญหาจริงๆ เท่านั้น การหมั่นตรวจสอบและปรับปรุงเงื่อนไขการแจ้งเตือนตามความเป็นจริงของระบบจะช่วยให้คุณเติบโตจากจูเนียร์ไปสู่โปรแกรมเมอร์ที่มืออาชีพ
ตัวอย่างการนำไปใช้จริง: หากคุณกำลังทำโปรเจกต์เว็บแอปพลิเคชัน ให้เริ่มจากการบันทึกเวลาที่ API ของคุณตอบสนองในแต่ละครั้งแทนที่จะตั้งค่าแจ้งเตือนทันที เมื่อผ่านไป 1 สัปดาห์ ให้ลองดึงข้อมูลเหล่านั้นมาดูว่าค่าเฉลี่ยอยู่ที่เท่าไหร่ และมีจุดไหนที่โดดออกมาบ้าง จากนั้นค่อยตั้งค่าแจ้งเตือนที่ "มีที่มา" โดยอ้างอิงจากข้อมูลจริงที่คุณเก็บมานั่นเอง
จงจำไว้ว่าระบบแจ้งเตือนที่ยอดเยี่ยมคือระบบที่เงียบที่สุดในเวลาที่ทุกอย่างปกติ และทำงานได้อย่างแม่นยำที่สุดในเวลาที่เกิดวิกฤต การให้ความสำคัญกับรายละเอียดเล็กๆ น้อยๆ ตั้งแต่วันนี้ จะช่วยให้คุณประหยัดเวลาและพลังงานในการแก้ไขปัญหาในอนาคตได้อย่างมหาศาลครับ
ที่มา: 4 Non-obvious learnings from working with alerts — DEV Community