Metryki i alerty: co mierzyć i kiedy budzić człowieka
Tysiące szeregów czasowych i dwieście powiadomień dziennie dają zero odpowiedzi i zespół, który przestał czytać kanał z alertami. Mały zestaw sygnałów i alerty, z których każdy wymaga działania.
Agent monitoringu zbiera z każdego serwera kilka tysięcy metryk, a system wysyła dwieście powiadomień dziennie: „CPU 81%”, „certyfikat wygasa za 89 dni”, „host niedostępny” po każdym planowanym restarcie. Po miesiącu zespół wycisza kanał z alertami. Kiedy w nocy zapełnia się dysk bazy danych, właściwe powiadomienie ginie wśród pozostałych, a o awarii informują użytkownicy rano.
Oba objawy mają wspólne źródło: metryki zbierane bez pytania, na które mają odpowiadać, i alerty ustawiane bez pytania, co ma zrobić osoba, która je dostanie. Poniżej mały zestaw sygnałów, z którego buduje się alerty, oraz zasady, dzięki którym alert o trzeciej w nocy jest naprawdę tego wart.
Co mierzyć: cztery sygnały i trzy pytania
Dla usługi widocznej dla użytkowników, niezależnie od technologii, wystarczą cztery sygnały. Dla każdego zasobu fizycznego lub wirtualnego wystarczą trzy pytania.
| Obiekt | Sygnał | Przykładowa metryka | Na co odpowiada |
|---|---|---|---|
| Usługa | Opóźnienie | 95. lub 99. percentyl czasu odpowiedzi | czy użytkownicy czekają |
| Usługa | Ruch | żądania na sekundę, aktywne sesje | kontekst dla pozostałych sygnałów |
| Usługa | Błędy | odsetek odpowiedzi 5xx, nieudane transakcje | czy żądania się udają |
| Usługa | Nasycenie | wykorzystanie puli połączeń do bazy, długość kolejki | jak blisko limitu jest najwęższy zasób |
| Zasób | Wykorzystanie | procent CPU, zajętość dysku, ruch na interfejsie | jaka część pojemności jest zajęta |
| Zasób | Nasycenie | kolejka procesora, czas oczekiwania na dysk, odrzucone pakiety | ile pracy czeka na zasób |
| Zasób | Błędy | błędy odczytu i zapisu, błędy interfejsu, retransmisje | czy zasób działa poprawnie |
Opóźnienie mierzy się percentylem, nie średnią. Średnia 300 ms może ukrywać, że co dwudziesty użytkownik czeka pięć sekund.
W środowisku Windows dochodzi kilka metryk spoza tych schematów: opóźnienie i błędy replikacji między kontrolerami domeny, liczba nieudanych uwierzytelnień w czasie, rozbieżność zegarów oraz wiek ostatniej udanej kopii zapasowej każdego systemu.
Czego nie zbierać
- Metryk co sekundę tam, gdzie decyzje zapadają w skali minut. Interwał 15–60 sekund wystarcza niemal zawsze.
- Metryk dla każdego procesu na każdej maszynie. Szczegóły procesu zbiera się tylko dla usług monitorowanych jako usługi.
- Wartości, które należą do logów: identyfikatorów użytkowników, adresów IP, numerów żądań. Każda unikalna kombinacja etykiet to osobny szereg czasowy, więc taka metryka rozsadza bazę. Metryka liczy, log opisuje; podział opisuję w tekście Strategia logowania.
Alert wymaga działania
Każdy alert odpowiada na pytanie: co ma zrobić osoba, która go dostanie? Jeśli odpowiedź brzmi „nic, tylko wiedzieć”, to jest informacja na pulpit. Jeśli brzmi „sprawdzić, czy to coś poważnego”, alert jest za szeroki i trzeba go zawęzić.
Alarmuje się na objawy widoczne dla użytkowników, nie na przyczyny. Odsetek błędów i czas odpowiedzi wychwytują każdą przyczynę, także tę, której nikt nie przewidział. CPU na 90% przy normalnym czasie odpowiedzi nie jest powodem, żeby kogokolwiek budzić; metryki zasobów służą do diagnozy po tym, jak alert na objaw już przyszedł.
Poziomy alertów i kanały
| Poziom | Kiedy | Kanał | Oczekiwana reakcja | Przykład |
|---|---|---|---|---|
| Budzi | usługa nie działa dla użytkowników albo zaraz przestanie | telefon lub aplikacja dyżurna, o każdej porze | minuty | odsetek błędów 5xx powyżej 5% przez 10 minut |
| Zgłoszenie | coś wymaga uwagi w ciągu dnia roboczego | zgłoszenie w systemie ITSM | ten sam lub następny dzień roboczy | dysk zapełni się w ciągu 7 dni |
| Tylko pulpit | trend, kontekst, ostrzeżenie | pulpit, raport tygodniowy | brak powiadomienia | CPU powyżej 85% w godzinach szczytu |
Alert bez przypisanego poziomu trafia na najniższy. W małej organizacji alertów poziomu „budzi” powinno być kilka w miesiącu, nie kilka dziennie.
Próg z czasem trwania w Zabbix
Okrągła liczba nie jest progiem. Próg wynika z historii: jeśli dysk zapełnia się o 1% tygodniowo, alert przy 80% daje miesiące zapasu, a jeśli o 5% dziennie, 80% to za późno. Do tego każdy alert ma warunek czasu trwania: chwilowy skok CPU podczas kopii zapasowej nie jest incydentem, 15 minut powyżej progu już tak.
Wyzwalacze w składni wprowadzonej w Zabbix 5.4 i obowiązującej w 6.0 LTS oraz nowszych:
# CPU powyżej 90% przez całe 15 minut (każda wartość z okresu)
min(/srv-app-01/system.cpu.util,15m)>90
# Scenariusz WWW „Portal” kończy się błędem przez 5 minut
min(/srv-web-01/web.test.fail[Portal],5m)>0
# Przy tempie z ostatniej doby /var osiągnie 95% w ciągu 7 dni
timeleft(/srv-app-01/vfs.fs.size[/var,pused],24h,95)<7d
Pierwsze dwa wyzwalacze mają poziom „budzi” albo „zgłoszenie” zależnie od usługi, trzeci zawsze „zgłoszenie”: daje tydzień na reakcję w godzinach pracy. Żeby problem nie migał na granicy progu, wyzwalacz dostaje osobne wyrażenie powrotu (Recovery expression), na przykład max(/srv-app-01/system.cpu.util,10m)<80. Problem zamyka się wtedy dopiero, gdy CPU przez 10 minut jest poniżej 80%.
Reguła Prometheus z czasem trwania
W Prometheus czas trwania określa pole for:. Warunek musi być spełniony przy każdej ewaluacji przez podany czas; wcześniej alert ma stan pending i nie trafia do Alertmanagera. Nazwy metryk i etykiet zależą od eksportera.
groups:
- name: portal
rules:
- alert: PortalHighErrorRate
expr: |
sum(rate(http_requests_total{job="portal", status=~"5.."}[5m]))
/ sum(rate(http_requests_total{job="portal"}[5m])) > 0.05
for: 10m
labels:
severity: page
annotations:
summary: "Portal: ponad 5% odpowiedzi z błędem 5xx od 10 minut"
runbook_url: "https://wiki.example.com/runbooks/portal-5xx"
- alert: DiskFullIn7Days
expr: predict_linear(node_filesystem_avail_bytes{mountpoint="/var"}[6h], 7 * 24 * 3600) < 0
for: 1h
labels:
severity: ticket
annotations:
summary: "{{ $labels.instance }}: /var zapełni się w ciągu 7 dni"
runbook_url: "https://wiki.example.com/runbooks/disk-full"
Etykieta severity decyduje o kanale. W Alertmanagerze trasa domyślna nie wysyła niczego, więc alert bez poziomu zostaje na pulpicie:
route:
receiver: dashboard-only # brak poziomu = brak powiadomienia
group_by: [alertname, job]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- matchers: ['severity="page"']
receiver: on-call
- matchers: ['severity="ticket"']
receiver: itsm
repeat_interval: 24h
receivers:
- name: dashboard-only
- name: on-call # tu konfiguracja powiadomień dyżurnych
- name: itsm # tu webhook tworzący zgłoszenie
Grupowanie, okna serwisowe i eskalacja
Awaria jednego przełącznika generuje sto alertów o niedostępności, po jednym na każdy host za nim. Osoba dyżurna potrzebuje jednego. W Zabbix służą do tego zależności wyzwalaczy: problem hosta nie jest zgłaszany, gdy aktywny jest problem przełącznika, od którego zależy. W Alertmanagerze group_by łączy alerty w jedno powiadomienie, a reguły inhibit_rules wyciszają alerty usług, gdy aktywny jest alert o niedostępnym węźle.
Planowane prace są częścią procesu zmian: okres konserwacji w Zabbix albo wyciszenie (silence) w Alertmanagerze zakłada się przed restartem, z numerem zgłoszenia w komentarzu. Alert poziomu „budzi” bez potwierdzenia w ustalonym czasie, na przykład 15 minut, trafia do następnej osoby. Reguła eskalacji jest zapisana, żeby nikt o trzeciej w nocy nie zastanawiał się, kogo obudzić.
Każdy alert z instrukcją postępowania
Alert bez instrukcji jest testem wiedzy osoby dyżurnej przeprowadzanym w najgorszych warunkach. Instrukcja jest krótka i ma stałą strukturę:
Co oznacza: ponad 5% odpowiedzi portalu kończy się błędem 5xx od 10 minut
Wpływ: część użytkowników nie może się zalogować ani zapisać danych
Sprawdź: 1. pulpit „Portal”: który endpoint zwraca błędy
2. log aplikacji z ostatnich 15 minut: wyjątki, przekroczenia czasu bazy
3. czy w ostatniej godzinie było wdrożenie
Obejście: wycofanie ostatniego wdrożenia albo restart puli aplikacji
Eskalacja: właściciel aplikacji, jeśli po 30 minutach nie ma poprawy
Odnośnik do instrukcji jest częścią alertu: w Prometheus jako adnotacja runbook_url, w Zabbix w polu URL wyzwalacza. Dzięki temu trafia do powiadomienia razem z treścią alertu.
Retencja dwupoziomowa
| Poziom | Rozdzielczość | Okres przechowywania | Do czego |
|---|---|---|---|
| Dane surowe | interwał zbierania, 15–60 s | 7–14 dni | diagnoza incydentu |
| Agregaty | godzinowe minimum, średnia i maksimum | 12 miesięcy lub dłużej | planowanie pojemności, trendy |
W Zabbix ten podział jest wbudowany: każda pozycja ma osobny okres przechowywania historii (na przykład 14 dni) i trendów (na przykład 365 dni), a trendy to właśnie godzinowe agregaty. Lokalna baza Prometheus ma jedną retencję, ustawianą parametrem --storage.tsdb.retention.time. Dane długoterminowe przechowuje się więc zwykle w osobnym systemie, do którego trafiają zagregowane szeregi z reguł nagrywających (recording rules).
Przegląd raz w miesiącu
Raz w miesiącu zespół przegląda alerty z ostatnich 30 dni w dwóch grupach. Pierwsza to najgłośniejsze alerty: te, które wystrzeliły najczęściej albo trwały najdłużej. Druga to alerty bez reakcji: niepotwierdzone, bez zgłoszenia i bez śladu działania. Alert, który przez miesiąc wystrzelił dziesięć razy i za każdym razem nikt nic nie zrobił, jest poprawiany, degradowany do pulpitu albo usuwany. Liczba alertów maleje, a zaufanie do kanału rośnie.
Sprawdź u siebie
Które reguły alertów nie mają czasu trwania, poziomu albo instrukcji:
curl -s http://prometheus.example.com:9090/api/v1/rules \
| jq -r '.data.groups[].rules[]
| select(.type == "alerting")
| select(.duration == 0 or .labels.severity == null or .annotations.runbook_url == null)
| .name'
Pusty wynik jest dobry. Każda nazwa na liście to reguła do uzupełnienia: brak for: oznacza alert na chwilowy skok, brak severity alert, który nigdzie nie trafi, brak runbook_url alert bez instrukcji.
Które alerty były najgłośniejsze w ostatnich 30 dniach:
curl -sG http://prometheus.example.com:9090/api/v1/query \
--data-urlencode 'query=topk(10, sum by (alertname) (count_over_time(ALERTS{alertstate="firing"}[30d])))' \
| jq -r '.data.result[] | "\(.value[1])\t\(.metric.alertname)"'
Wynik to liczba ewaluacji w stanie firing; przy interwale ewaluacji jednej minuty odpowiada liczbie minut. Alert, który przez miesiąc był aktywny przez tysiące minut, sygnalizuje stały problem, którego nikt nie rozwiązuje, albo źle ustawiony próg. W Zabbix podobną listę daje raport Reports → Top 100 triggers za okres 30 dni.
Które alerty są wyciszone i od jak dawna:
amtool silence query --alertmanager.url=http://alertmanager.example.com:9093
Każde wyciszenie powinno mieć komentarz z numerem zgłoszenia i datę końca w ciągu dni, nie tygodni. Wyciszenie odnawiane od miesięcy to alert bez reakcji, tylko lepiej ukryty.