สารบัญ
- ทำไมระบบมอนิเตอร์ส่วนใหญ่จึงสร้างสัญญาณรบกวนมากกว่าสัญญาณจริง
- แนวทางสามระดับ
- Sentry: เลิกถูกเรียกทุกครั้งที่มี exception ของ Python
- Prometheus และ AlertManager: จัดเส้นทางตามความรุนแรง
- AWS CloudWatch: SNS → Lambda → Echobell
- ทำให้การจัดเส้นทางการแจ้งเตือนเป็นการตัดสินใจของทีม
- บททดสอบสัญญาณต่อสัญญาณรบกวน
- เปลี่ยนทีละอย่าง
- เนื้อหาที่เกี่ยวข้อง
มันมีชื่อเรียกของมัน: อาการล้าจากการแจ้งเตือน (alert fatigue) คือสิ่งที่เกิดขึ้นเมื่อเครื่องมือมอนิเตอร์ของคุณส่งการแจ้งเตือนมามากจนสมองเริ่มกรองมันทิ้งเองโดยอัตโนมัติ แม้แต่อันที่สำคัญจริง ๆ
มันมักเริ่มจากเรื่องเล็ก ๆ คุณตั้งการแจ้งเตือนทางอีเมลสำหรับข้อผิดพลาด 5xx ทุกครั้ง จากนั้นก็ตั้งการแจ้งเตือนใน Slack สำหรับทุกบิลด์ที่ล้มเหลว แล้วก็มี Datadog เด้ง อีเมลจาก Sentry ข้อความจาก UptimeRobot ภายในเดือนเดียว มือถือคุณสั่นวันละ 50 ครั้งและไม่มีอะไรรู้สึกเร่งด่วนเลย ส่วนที่แย่จริง ๆ คืออะไร? พอมีอะไรพังขึ้นมาจริง ๆ คุณก็ฝึกตัวเองให้เพิกเฉยไปเรียบร้อยแล้ว
อาการล้าจากการแจ้งเตือนฆ่าเวลาตอบสนอง และเวลาตอบสนองที่ช้าก็ฆ่าผลิตภัณฑ์
ทำไมระบบมอนิเตอร์ส่วนใหญ่จึงสร้างสัญญาณรบกวนมากกว่าสัญญาณจริง
ปัญหาพื้นฐานคือเครื่องมือแจ้งเตือนส่วนใหญ่ปฏิบัติกับทุกอีเวนต์เหมือนกันหมด เทสต์ที่ล้มเหลวแบบไม่คงเส้นคงวา 10% ของเวลาทั้งหมด ได้รูปแบบการแจ้งเตือนเดียวกับ "API การชำระเงินคืนค่า 500 ให้ผู้ใช้ทุกคน" อันหนึ่งควรโทรปลุกคุณตอนตีสอง อีกอันน่าจะแค่โผล่ในสรุปประจำสัปดาห์ก็พอ
เมื่อทุกอย่างได้รับการปฏิบัติเหมือนกัน คนก็เริ่มเพิกเฉยกับทุกอย่าง
ทางแก้ไม่ใช่การลดจำนวนการแจ้งเตือน แต่คือการส่งที่ฉลาดขึ้น อีเวนต์เดียวกันที่ระดับความรุนแรงต่างกัน หรือที่ความถี่ต่างกัน ควรให้ความเร่งด่วนบนมือถือของคุณต่างกันด้วย
แนวทางสามระดับ
Echobell ให้โหมดการส่งการแจ้งเตือนสามแบบ และการใช้ทั้งสามแบบให้ดีคือหัวใจทั้งหมด:
- ปกติ (Active): การแจ้งเตือนแบบพุชมาตรฐาน เหมาะกับอีเวนต์เชิงข้อมูลที่ไม่ต้องลงมือทำทันที
- สำคัญตามเวลา: ทะลุโหมดโฟกัสของ iOS ได้ เหมาะกับเรื่องที่ต้องจัดการภายในหนึ่งถึงสองชั่วโมงข้างหน้า
- โทรเข้า: ทำให้มือถือของคุณดังเหมือนสายเรียกเข้า สงวนไว้ให้เรื่องประเภท "แก้เดี๋ยวนี้ ไม่งั้นเกิดผลเสียจริง"
เป้าหมายคือรักษาระดับโทรเข้าไว้ให้อีเวนต์ที่การตอบสนองช้าแล้วมีผลกระทบจริง เช่น รายได้ที่หายไป ความล้มเหลวลูกโซ่ หรือข้อมูลผู้ใช้ที่เสี่ยง ส่วนที่เหลือให้ลดลงมาเป็นสำคัญตามเวลาหรือต่ำกว่านั้น
Sentry: เลิกถูกเรียกทุกครั้งที่มี exception ของ Python
Sentry คือตัวอย่างคลาสสิกของอาการล้าจากการแจ้งเตือน ค่าเริ่มต้นของมันคือส่งอีเมลหาคุณทุกครั้งที่มี issue ประเภทใหม่ ในโค้ดเบสที่มีความเคลื่อนไหวช่วงสัปดาห์ปกติ นั่นคือสายน้ำที่ไหลไม่หยุด
นี่คือการตั้งค่าที่ฉลาดกว่า:
- ใน Sentry ไปที่ Alerts → Create Alert → Issue Alert
- เพิ่มเงื่อนไข:
The issue is seen more than 10 times in 1 hour - เพิ่มการกระทำ: Send a notification via webhook → วาง URL ของช่อง Echobell ของคุณ
- ตั้งประเภทการแจ้งเตือนของช่องเป็น
time-sensitive
สำหรับเส้นทางที่วิกฤตจริง ๆ เช่น exception ที่ไม่ถูกจัดการในโฟลว์การชำระเงิน การยืนยันตัวตนล้มเหลว หรือข้อมูลเสียหาย ให้สร้างการแจ้งเตือนแยกอีกอันที่มีเกณฑ์ต่ำกว่า และใช้ช่อง Echobell ระดับ calling ช่องนั้นจะดังเฉพาะเมื่อมีอะไรพังในเส้นทางเจาะจงนั้นเท่านั้น
ผลลัพธ์: issue ทั่วไปสะสมเงียบ ๆ อยู่ในแดชบอร์ด Sentry ส่วนปัญหาที่ทำให้โปรดักชันพังจะโทรเข้ามือถือคุณ
Prometheus และ AlertManager: จัดเส้นทางตามความรุนแรง
ถ้าคุณใช้ Prometheus อยู่ คุณก็มี AlertManager คอยจัดเส้นทางให้อยู่แล้ว คุณส่งการแจ้งเตือนตรงไปยัง Echobell ได้โดยเพิ่มมันเป็น webhook receiver
ในไฟล์ alertmanager.yml ของคุณ:
receivers:
- name: echobell-critical
webhook_configs:
- url: https://hook.echobell.one/t/<channel-token>
send_resolved: true
- name: slack-warnings
slack_configs:
- api_url: YOUR_SLACK_WEBHOOK
route:
group_by: ['alertname', 'job']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: slack-warnings
routes:
- match:
severity: critical
receiver: echobell-critical
ด้วยการตั้งค่านี้ การแจ้งเตือนที่มี severity: critical จะไปยัง Echobell และโทรเข้ามือถือคุณ ส่วนคำเตือนจะไป Slack ที่รอถึงเช้าได้ คุณไม่ต้องแก้กฎของ Prometheus แม้แต่ข้อเดียว แค่เพิ่มชั้นการจัดเส้นทางใน AlertManager เท่านั้น
ตั้งช่อง Echobell เองให้เป็น โทรเข้า เพราะถ้า AlertManager ติดป้ายว่า critical มันก็คู่ควรกับเสียงเรียกเข้าจริง ๆ
AWS CloudWatch: SNS → Lambda → Echobell
CloudWatch ไม่มีเอาต์พุตแบบ webhook ในตัว แต่คุณไปถึงจุดนั้นได้ในไม่กี่นาทีด้วย SNS และฟังก์ชัน Lambda เล็ก ๆ
- สร้าง SNS topic แล้วผูกเข้ากับ CloudWatch alarm ของคุณ
- สร้างฟังก์ชัน Lambda ที่ subscribe topic นั้น:
import json
import urllib.request
def lambda_handler(event, context):
message = json.loads(event['Records'][0]['Sns']['Message'])
alarm_state = message.get('NewStateValue', 'UNKNOWN')
payload = {
"title": f"AWS: {message['AlarmName']}",
"body": message.get('NewStateReason', 'No details'),
"notificationType": "calling" if alarm_state == "ALARM" else "active"
}
req = urllib.request.Request(
'https://hook.echobell.one/t/<channel-token>',
data=json.dumps(payload).encode(),
headers={'Content-Type': 'application/json'},
method='POST'
)
urllib.request.urlopen(req)
รูปแบบนี้ใช้ได้กับทุกบริการของ AWS ที่รองรับ SNS ทั้งอีเวนต์ของ RDS ความล้มเหลวของบริการ ECS การแจ้งเตือนเมื่อค่าใช้จ่ายถึงเกณฑ์ และการเปลี่ยนสถานะของ EC2 instance เพิ่ม Lambda หนึ่งตัว ต่อเข้ากับ SNS แล้วทุก CloudWatch alarm ก็กลายเป็นสายโทรเมื่อมันทำงานจริง
ทำให้การจัดเส้นทางการแจ้งเตือนเป็นการตัดสินใจของทีม
พลังที่แท้จริงของการแจ้งเตือนแบบแบ่งระดับคือการทำให้การตัดสินใจเรื่องเส้นทางชัดเจน ไม่ใช่แค่สิ่งที่คนคนหนึ่งเคยตั้งไว้ครั้งเดียวแล้วไม่มีใครหาเจอ
โครงสร้างที่ใช้ได้จริงสำหรับทีมวิศวกรรมเล็ก ๆ:
| ช่อง | ประเภท | ใครติดตาม |
|---|---|---|
production-api-critical | โทรเข้า | วิศวกรที่เข้าเวร on-call |
production-api-warnings | สำคัญตามเวลา | ทีมพัฒนาทั้งทีม |
staging-all | ปกติ | ทีมพัฒนา (ไม่บังคับ) |
background-jobs | ปกติ | ใครก็ได้ที่สนใจ |
เมื่อรอบเวร on-call เปลี่ยน คนที่ออกเวรก็เลิกติดตามช่องวิกฤต แล้วคนที่เข้าเวรก็กดติดตาม เท่านี้ก็ส่งต่อเวรครบแล้ว ไม่ต้องมีไฟล์คอนฟิก ไม่ต้องมีหน้าจอผู้ดูแลระบบ
ช่องของ Echobell แชร์ผ่านลิงก์ได้ การกดติดตามจึงใช้เวลาราว 10 วินาทีต่อสมาชิกใหม่หนึ่งคน
บททดสอบสัญญาณต่อสัญญาณรบกวน
ก่อนเพิ่มการแจ้งเตือนใหม่ทุกครั้ง ให้ถามคำถามเดียว: ถ้ามันดังขึ้นตอนตีสามของวันศุกร์ ฉันจะทำอะไรกับมันจริง ๆ
- "ตื่นขึ้นมาแก้เดี๋ยวนี้" → โทรเข้า
- "จัดการเป็นเรื่องแรกตอนเช้า" → สำคัญตามเวลา หรือปกติ
- "คงไม่ทำอะไร นอนต่อ" → ให้ทบทวนว่าการแจ้งเตือนนี้ควรมีอยู่หรือไม่
ระบบมอนิเตอร์ส่วนใหญ่มีของอยู่ในกลุ่มแรกมากเกินไป และในกลุ่มที่สองน้อยเกินไป คำตอบที่ถูกต้องสำหรับอีเวนต์ส่วนใหญ่คือ "ค่อยจัดการพรุ่งนี้" และการแจ้งเตือนแบบสำคัญตามเวลาที่ขึ้นบนหน้าจอล็อกโดยไม่ส่งเสียงเรียกเข้า ก็คือเครื่องมือที่เหมาะกับกรณีนั้นพอดี
เปลี่ยนทีละอย่าง
ถ้าระบบปัจจุบันของคุณกำลังสร้างอาการล้าจากการแจ้งเตือน ทางแก้ที่เร็วที่สุดไม่ใช่การรื้อใหม่ทั้งหมด ให้เลือกแหล่งที่ส่งเสียงดังที่สุด ซึ่งน่าจะเป็นอีเมลจาก Sentry หรือห้อง Slack ที่ทุกคนปิดเสียงไปแล้ว จากนั้นจัดหมวดอีเวนต์แต่ละประเภทว่าเป็นโทรเข้า สำคัญตามเวลา หรือปกติ
หนึ่งแหล่ง หนึ่งสัปดาห์ แล้วดูว่าสัญญาณรบกวนลดลงโดยไม่เสียสัญญาณจริงไปไหม
จากนั้นค่อยทำแหล่งถัดไป
ระบบแจ้งเตือนที่จูนมาดีเป็นหนึ่งในสิ่งที่ค่อย ๆ ทำให้ชีวิตการทำงานประจำวันของคุณดีขึ้นอย่างเงียบ ๆ โดยไม่ต้องมีดราม่า คุณจะเลิกกลัวมือถือของตัวเอง และเริ่มเชื่อได้ว่าถ้ามันดังขึ้นมา มันสำคัญจริง