ใช้ Elasticsearch alerts บอกเมื่อเรา "เกือบว่าง"
ที่ ObjectRocket เราเพลิงออฟฟิศด้วย cold brew coffee on tap ร้อนมากใน Austin, TX ในเดือนสิงหาคม เราต้องการ caffeine เย็น
เนื่องจากเราเก็บแค่ single keg ในแต่ละครั้ง การจัดตารางออเดอร์โดยไม่ให้หมดเป็นเรื่อง tricky ดังนั้นเมื่อมีคนใน ObjectRocket office บอกว่า "อยากได้ข้อมูลการใช้ cold brew ที่ดีกว่า" ผมกूदเข้าไปทันที ผมมองหาวิธีใหม่ๆ ที่จะแสดงให้เห็นว่า Elastic Stack ทำได้อะไร ดังนั้นผมออกมาเพื่อสร้างระบบ monitoring และ alerting แบบ semi-autonomous เพื่อเราจะไม่มี cold brew หมดอีกเลย
สิ่งที่เราได้คือ combination ของ Raspberry Pi, Elasticsearch, Kibana, และ Sentinl/ElastAlert เพื่อยิง alerts ไป Slack เมื่อมีสิ่งสำคัญเกิดขึ้นกับถัง Sentinl และ ElastAlert เป็นดาวเด่นของรายการ เราจะเจาะลึกในภายหลัง
ในส่วนแรกของชุด 2 ส่วนนี้ เราจะสำรวจว่าผมสร้าง alert system ด้วยข้อมูลที่ capture จาก kegerator solution ของเราอย่างไร ความหวังคือคุณจะเดินทางไปพร้อมกับ ideas และ knowledge บางอย่างเกี่ยวกับ open source alerting options สำหรับ Elasticsearch ผมจะเก็บรายละเอียดการสร้าง physically ไว้ในโพสต์ถัดไป
Data (ไม่ใช่แค่ cold brew) จาก Keg
เช่นที่ระบุ เราจะพูดถึง kegerator build-out ในบล็อกถัดไป และทำไมเราเลือก scale-keg-weight solution แทน flow rate monitoring system
สิ่งที่คุณต้องรู้สำหรับบล็อกนี้คือ ผมตั้งค่า Raspberry Pi-powered scale ที่ส่ง stream ของ documents ไป Elasticsearch ในรูปแบบแบบด้านล่าง
{ "_index": "filebeat-6.2.4-2018.05.15", "_type": "doc", "_source": { "@timestamp": "2018-05-15T16:50:49.000Z", "beat": { "hostname": "raspberrypi", "name": "raspberrypi", "version": "6.2.4" }, "weight": 58.4, "message": "2018-05-15T16:50:49+0000 - -0.4" } }
Filebeat ดึงข้อมูลและรวมสอง main fields ที่เราสนใจ:
- "@timestamp" ของแต่ละ weight reading
- "weight" reading จริงที่ timestamp นั้น
Alerting Options
First things first: เพื่อดำเนินการเมื่อมีบางอย่างผิดปกติกับถัง ผมต้องการวิธีส่ง notifications ไปยัง key persons นั่นคือที่ alerting package เข้าเล่น
โชคดีที่มี Apache 2.0 licensed options หลายอย่างที่เพิ่ม alerting ให้ Elasticsearch cluster: ElastAlert และ Sentinl
ElastAlert
ElastAlert เป็น flexible alerting framework สำหรับ Elasticsearch สร้างโดย Yelp ที่รันแยกจาก Elasticsearch และถูกกำหนดค่าหลักผ่าน basic config files ผู้ใช้สามารถสร้าง main config file ด้วย global parameters ทั่วทั้ง alerts แล้วสร้าง rules files สำหรับแต่ละ rule ที่มี ElastAlert-specific YAML เพื่อกำหนด rules และ alerts ที่ผลลัพธ์ แต่ละ "rule" ประกอบด้วย:
- Rule configuration ตาม standard list of rules (เช่น "flatline", "spike", และ "metric aggregation")
- Elasticsearch filters เพื่อจำกัด query hits ที่แต่ละ rule ใช้
- Alert ที่ยิงเมื่อ rule portion เป็น positive (เช่น email, Jira, Slack, ฯลฯ)
Sentinl
Sentinl ใหม่กว่า ElastAlert นิดหน่อย ObjectRocket พบ Sentinl—สร้างโดย Siren Solutions—ขณะหา alerting options ใหม่สำหรับลูกค้าบน ObjectRocket Service Sentinl เป็น Kibana plugin ที่เสนอ reporting นอกจาก alerting สำหรับ Elasticsearch มันเรียกแต่ละ job ว่า "watcher" (ไม่สับสนกับ plugin เก่าที่มีชื่อเดียวกัน) รวมถึง:
- Schedule (บ่อยแค่ไหนและเมื่อไหร่ที่จะตรวจสอบ)
- Input query (Elasticsearch query สำหรับข้อมูลที่คุณต้องการตรวจสอบ)
- Condition (logic ที่ตัดสินใจว่าจะ alert บนข้อมูลหรือไม่)
- Transform (โค้ดแก้ไขข้อมูลก่อน alert)
- Actions (ทำอะไรเมื่อ alert เช่น Slack, Email, หรือ webhook)
Alerting Option ใดเหมาะกับคุณ?
ทั้งคู่ดีมาก แค่ขึ้นอยู่กับประเภท alerts ที่คุณมองหา นี่คือ findings ของผม:
| ElastAlert | Sentinl | |
| Pros |
|
|
| Cons |
|
|
การสร้าง Alerts
ตอนนี้ผมต้องกำหนดว่า alerts ประเภทไหนที่ต้องสร้าง สิ่งที่ผมอยากรู้สุดท้ายคือเมื่อไหร่ควรสั่ง cold-brew เพิ่ม ผมต้องสร้าง alerts ที่บอกเราว่า:
Keg Empty / Nearly empty
ค่อนข้างง่าย: รายงานหาก weight ตกต่ำกว่า threshold ที่กำหนดเป็น "empty"
Keg has been replaced
อ่า มีกาแฟสด: ตรวจจับเมื่อมี sharp increase ใน weight
Monitoring is broken
ไม่มี data, ไม่มี alerts: เราต้องรู้เมื่อ scale หยุดส่งข้อมูล
Keg Empty / Nearly Empty
ในสถานการณ์นี้ ผมตั้ง alert หาก weight ต่ำกว่า designated threshold ที่ถือว่า "empty" และเตือนเราหาก weight บ่งชี้ว่ามีประมาณ 20% ของถังเหลือ
ElastAlert
ElastAlert ทำให้ง่ายด้วย metric aggregation rule type: สร้าง aggregation จาก metric แล้วตัดสินใจว่ามัน above หรือ below specific threshold
# (Required)
# Rule name, must be unique
name: Empty Alarm
# (Required)
# Type of alert.
type: metric_aggregation
# (Required)
# Index to search, wildcard supported
index: filebeat-*
# How much data should we use
buffer_time: hours: 1
# How often can we send this alert?
realert: hours: 24
# Type of elasticsearch document to use
doc_type: doc
metric_agg_key: weight
metric_agg_type: max
min_threshold: 41
# (Required)
# The alert is use when a match is found
alert:
- "slack"
alert_subject: The cold brew keg is empty
alert_text_type: alert_text_only
alert_text: "The cold brew keg is empty. Panic."
slack:
slack_webhook_url: "https://hooks.slack.com/services/foo/bar"
slack_msg_color: danger
slack_emoji_override: ":torch-and-pitchfork:"
ผมตั้งให้ดูย้อนหลัง 1 ชั่วโมง (buffer_time) สำหรับ max weight ต่ำกว่า 41 (ถังว่าง) และต้องการส่ง alert เพียงครั้งทุก 24 ชั่วโมง จากนั้น ผมสามารถกำหนดค่า Slack alerts, ประเภทข้อมูลที่ส่งใน alerts และแม้แต่รายละเอียดเกี่ยวกับสีและ emoji ที่ใช้
มันมี trickiness นิดหน่อยสำหรับ warning alerts ผมอยากรู้ตอนมันอยู่ใน warning threshold: มากกว่า 41 (empty) แต่น้อยกว่า 65 (25% mark เพื่อเริ่มเตือนว่าเราเกือบหมด cold brew) เนื่องจาก ElastAlert ให้แค่ single threshold ผมใช้ filters ของพวกเขาเพื่อแก้
metric_agg_key: weight
metric_agg_type: avg
min_threshold: 65
filter:
- range:
weight:
gte: 41
ผม filter เพื่อประเมิน weights greater than or equal to 41 เพราะถ้า weights ทั้งหมดต่ำกว่า 41 ผมไม่อยากให้ alert นี้ trigger (เพราะ "empty" alert จะทำ) อย่างไรก็ตาม หากมี weights บางส่วนเท่ากับ 41 หรือมากกว่า "empty" alert จะไม่ trigger และผมสามารถตัดสินใจว่า average ตรงตาม requirement น้อยกว่า 65 หรือไม่
Sentinl
Sentinl ให้ GUI ที่ใช้ง่ายสำหรับกำหนดค่า watcher
บนหน้าจอแรก แค่ตั้งชื่อ watcher และตั้ง schedule

Input คือ Elasticsearch query เพื่อดึงข้อมูลที่คุณต้องการ: docs ใดๆ ที่มี weight และสร้าง average aggregation บน weight field

ในหน้าจอ condition กำหนดว่าอะไร trigger alert: ต้องมี hits อย่างน้อยบางส่วน และ average weight ต้องต่ำกว่า 41

นี่คือ console alert (ซึ่งเก็บ document ใน special index ด้วย) ที่ยิงข้อความเมื่อ condition เป็น true

Sentinl มาพร้อม UI แต่คุณต้องเขียน queries (เล็กน้อย) มากกว่า อย่างไรก็ตาม พวกเขาก็คือ Elasticsearch queries ส่วนใหญ่ โอกาสคุณสบายใจกับพวกเขามาก
Keg has been refilled
ตอนนี้ผมต้องการวิธีส่ง announcement ทั่วไปไปยังออฟฟิศว่าถังถูกเติมแล้ว เนื่องจากเราบางครั้งได้รับถังขนาดต่างกัน แทนที่จะแค่มองหา level มากกว่า threshold แบบใดๆ ผมอยากมองหา sharp increase ใน weight
ElastAlert
ElastAlert รวม built-in ชื่อ "spike" เพื่อกำหนด upward increase ใน weight ของถัง:
name: Refill Detector
type: spike
index: filebeat-*
field_value: weight
spike_height: 2
spike_type: 'up'
timeframe: minutes: 10
threshold_ref: 100
threshold_cur: 100
realert: hours: 6
Rule นี้ดูค่าใน weight field และ bucket พวกเขาเข้า 10-minute windows หาก mean ของ weight สำหรับ window ใดๆ มากกว่า 2x (spike_height) ของ previous 10-minute window ผมอยากยิง alert นอกจากนี้ โปรดสังเกตว่าสำหรับ 10-minute window ให้ "valid" ต้องมีอย่างน้อย 100 samples (threshold_ref และ threshold_cur settings) และ alert ไม่สามารถยิงบ่อยกว่าทุก 6 ชั่วโมง
Sentinl
ด้าน Sentinl มันซับซ้อนนิดหน่อย แต่เราใช้ serial difference aggregation เพื่อตัดสินใจว่าเราเห็น buckets ใดๆ ที่มี huge increase over previous buckets:
{ "input": { "search": { "request": { "index": [ "filebeat-*" ], "body": { "query": { "bool": { "filter": [ { "range": { "@timestamp": { "gt": "now-5m/m" } } } ] } }, "aggs": { "30s_buckets": { "date_histogram": { "field": "@timestamp", "interval": "30s" }, "aggs": { "weight_avg": { "avg": { "field": "weight" } }, "weight_diff": { "serial_diff": { "buckets_path": "weight_avg", "lag": 3 } } } }, "max_weight_diff": { "max_bucket": { "buckets_path": "30s_buckets>weight_diff" } } } } } } }, "condition": { "script": { "script": "payload.hits.total > 20" }, "compare": { "payload.aggregations.max_weight_diff.value": { "gte": 40 } } } }
Watcher นี้สแกน 5 นาทีที่ผ่านมา แยกเป็น 30s buckets แล้วดูว่าความแตกต่างข้าม 3 buckets เป็นการเพิ่มอย่างน้อย 40 อีกครั้ง มันซับซ้อนกว่า ElastAlert equivalent นิดหน่อย แต่มันทำงานได้ดี
ผมไม่ได้แสดง alert ที่สาม ที่มองหา broken data feed ที่นี่ แต่ในทั้งสองกรณี มันเป็น alert ง่ายมาก ElastAlert's flatline จัดการได้ดี และ Sentinl เรียบง่ายเท่ากับการ grab all weight readings ใน window และนับ hits หากใครอยากดูโค้ด บอกเราได้
การใช้ Alert Data
ประโยชน์เพิ่มเติมของทั้งสองระบบ alerting คือพวกเขามีความสามารถในการ query actual alerts เนื่องจาก log ของ alerts ถูกเก็บใน Elasticsearch ทำให้คุณสร้าง visualizations บน alerts ได้
Refills
ผมใช้ refill alerts เพื่อ plot out เมื่อเราเห็น refill บน Kibana dashboard แทนที่จะดู weight data เพื่อสร้าง visualization ของ last refill time ผมแค่ดู last refill alert สำหรับ visualization ของผม Sentinl ตัวอย่าง เก็บ alerts ทั้งหมดใน local indexes ที่เรียก "watcher_alerts-*" ตาม date

เพื่อสร้าง visualization บน last refill ให้ filter events โดย "watcher" field เพื่อให้ได้แค่ refill events แล้วเลือก max date

Daily Reporting
อีกตัวเลือกที่ดีคือคุณสามารถใช้ regular alert เพื่อสร้าง behavior คล้าย roll-up ที่คุณสามารถ report ได้ในภายหลัง
ตัวอย่าง: หากผมอยากดู daily consumption amount ผมดู weight decreases วันต่อวัน filter out large spikes (เพราะ refills หรือ events อื่นๆ) และแปลง weight เป็น ounces
สิ่งนี้อาจ tricky กับ single Kibana visualization นิดหน่อย (อย่างไรก็ตาม Vega ดูมีพอทENCY)
แทนที่จะทำนั้น ผมสร้าง daily alert ที่รันทุกคืนก่อนเที่ยงคืน และสร้าง sum ของ consumption สำหรับวันนั้น จากนั้นสร้าง simple visualization ที่อ่าน daily sums จาก "watcher_alerts" indexes


ผลลัพธ์สุดท้าย
เมื่อผมติดตั้งเสร็จ Slack ตอนนี้บอกเราเมื่อต้องสั่ง cold brew kegs เพิ่ม และไม่ได้ส่งไปแค่ IT หรือ admins หรือกลุ่มคนเฉพาะบางคน ทั้งออฟฟิศตอนนี้รู้เมื่อถังใหม่มาถึง

ไม่มี cold sweats สำหรับ cold brew ที่นี่: staff happiness และ productivity อยู่ที่ all-time high
Elasticsearch + Sentinl/ElastAlert alerting FTW!