Kai monitoringas tampa menu
Prisimenu laikus, kai serverių monitoringas reiškė žiūrėjimą į juodus terminalus su žaliomis raidėmis ir bandymą suprasti, kas vyksta su sistema. Dabar turime Prometheus ir Grafana – duetą, kuris pavertė nuobodų metrikų rinkimą į beveik meninę patirtį. Bet ne vien grožis čia svarbu – tai realiai veikiantis įrankių rinkinys, kuris gali išgelbėti jūsų infrastruktūrą nuo katastrofos.
Prometheus atsirado Google Borgmon įkvėptas, o Grafana pradėjo gyvenimą kaip Kibana alternatyva. Šiandien šie du įrankiai tapo de facto standartu cloud-native pasaulyje. Ir ne be priežasties – jie tiesiog veikia, ir veikia gerai.
Kodėl Prometheus nėra dar viena monitoringo sistema
Daugelis monitoringo sistemų veikia push principu – agentai siunčia duomenis į centrinį serverį. Prometheus daro priešingai – jis pats ateina ir pasiima tai, ko jam reikia. Šis pull modelis iš pradžių gali atrodyti keistas, bet praktikoje tai genialus sprendimas.
Pirma, jums nereikia konfigūruoti kiekvieno agento, kad jis žinotų, kur siųsti duomenis. Antra, lengviau testuoti – tiesiog paleiskite aplikaciją lokalioje mašinoje ir patikrinkite /metrics endpointą. Trečia, dinamiškose aplinkose (Kubernetes, Docker Swarm) Prometheus automatiškai atranda naujus target’us per service discovery mechanizmus.
Prometheus saugo duomenis time-series duomenų bazėje, optimizuotoje būtent metrikoms. Kiekviena metrika turi pavadinimą ir labels – raktas-reikšmė poras, kurios leidžia lanksčiai filtruoti ir grupuoti duomenis. Pavyzdžiui:
http_requests_total{method="GET", endpoint="/api/users", status="200"} 1547
Čia matome ne tik bendrą skaičių, bet ir kontekstą – kokio tipo užklausos, į kurį endpointą, su kokiu statusu. Tai leidžia rašyti galingas PromQL užklausas, kurios atskleidžia tikrąją sistemos būklę.
PromQL: užklausų kalba, kuri neišgąsdins
Kai pirmą kartą susidūriau su PromQL, pagalvojau – dar viena užklausų kalba, kurią reikės mokytis. Bet iš tiesų ji intuityvesnė nei atrodo. Pradėkime nuo paprasto pavyzdžio – norime sužinoti, kiek užklausų per sekundę gauna mūsų API:
rate(http_requests_total[5m])
Funkcija rate() apskaičiuoja vidutinį augimo greitį per nurodytą laiko langą. Tai būtent tai, ko jums reikia counter tipo metrikoms. Jei norite matyti tik GET užklausas:
rate(http_requests_total{method="GET"}[5m])
Dabar įdomesnis dalykas – norime sužinoti 95-ąjį percentilį atsakymo laiko. Čia praverčia histogram metrikos:
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
Taip, atrodo sudėtingiau, bet esmė paprasta – histogram_quantile funkcija apskaičiuoja percentilį iš histogram duomenų. Kodėl tai svarbu? Nes vidutinis (average) atsakymo laikas gali būti 100ms, bet jei 5% vartotojų laukia 10 sekundžių, turite problemą, kurios vidurkis neparodo.
Galite sudėti, atimti, dauginti metrikos. Pavyzdžiui, skaičiuojant error rate:
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])
Čia naudojame regex status=~"5.." sugauti visus 5xx statusus. Padalinus iš bendro užklausų skaičiaus, gauname klaidų procentą.
Grafana: kai duomenys tampa istorija
Prometheus surenka duomenis, bet Grafana juos paverčia suprantama istorija. Ir čia prasideda tikroji magija. Grafana palaiko daugybę duomenų šaltinių – Prometheus, InfluxDB, Elasticsearch, net paprastas PostgreSQL. Bet su Prometheu ji veikia ypač sklandžiai.
Kurdami dashboard’ą, nepulkite iškart kurti dešimčių panelių. Pradėkite nuo keturių aukso signalų (four golden signals), kuriuos Google SRE komanda propaguoja:
- Latency – kiek laiko užtrunka užklausos
- Traffic – kiek užklausų gaunate
- Errors – kiek užklausų baigiasi klaida
- Saturation – kaip pilnai išnaudojami resursai
Šie keturi rodikliai duoda 80% informacijos apie sistemos sveikatą. Kitus 20% pridėsite vėliau, kai suprasite, ko konkrečiai jums trūksta.
Grafana panelių tipai nėra tik grafikų reikalas. Gauge puikiai tinka rodyti CPU ar memory usage – matote ne tik dabartinę reikšmę, bet ir ar artėjate prie limito. Stat paneliai geri vienam skaičiui – pavyzdžiui, aktyvių vartotojų skaičiui. Heatmap’ai puikiai rodo latency pasiskirstymą laike.
Exporteriai: kaip Prometheus supranta viską
Prometheus pats savaime nieko nežino apie jūsų sistemą. Jam reikia exporterių – mažų programų, kurios konvertuoja įvairius metrikų formatus į Prometheus suprantamą formatą.
Node exporter – būtinas dalykas bet kuriam serveriui. Jis eksportuoja CPU, memory, disk, network metrikos. Diegimas Ubuntu serveryje paprastas:
wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz
tar xvfz node_exporter-1.6.1.linux-amd64.tar.gz
cd node_exporter-1.6.1.linux-amd64
./node_exporter
Paleiskite kaip systemd service, ir turite bazinį serverio monitoringą. Prometheus konfigūracijoje pridėkite:
scrape_configs:
- job_name: 'node'
static_configs:
- targets: ['localhost:9100']
Jei naudojate PostgreSQL, MySQL, Redis, MongoDB – visiems yra oficialūs ar community palaikomi exporteriai. Blackbox exporter leidžia monitorinti HTTP, DNS, TCP, ICMP endpointus iš išorės – puikus būdas patikrinti, ar jūsų servisas pasiekiamas.
Bet kas, jei naudojate custom aplikaciją? Tuomet reikia instrumentuoti kodą. Prometheus klientų bibliotekos egzistuoja visoms populiarioms kalboms. Python pavyzdys:
from prometheus_client import Counter, start_http_server
requests_total = Counter('http_requests_total', 'Total HTTP requests', ['method', 'endpoint'])
@app.route('/api/users')
def get_users():
requests_total.labels(method='GET', endpoint='/api/users').inc()
# jūsų kodas čia
start_http_server(8000) # metrikos bus /metrics endpointe
Alerting: kai metrikos šaukia pagalbos
Gražūs dashboard’ai yra puiku, bet negalite visą laiką žiūrėti į ekraną. Čia ateina Alertmanager – Prometheus komponentas, atsakingas už alert’ų valdymą.
Alert’ai apibrėžiami Prometheus konfigūracijoje kaip rules. Pavyzdžiui, norite gauti pranešimą, kai API error rate viršija 5%:
groups:
- name: api_alerts
rules:
- alert: HighErrorRate
expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) > 0.05
for: 5m
labels:
severity: critical
annotations:
summary: "High error rate detected"
description: "Error rate is {{ $value | humanizePercentage }}"
Parametras for: 5m svarbus – alert’as nesuveiks iškart, o tik jei sąlyga išlieka tiesa 5 minutes. Tai išvengia false positive dėl trumpalaikių spike’ų.
Alertmanager gali siųsti pranešimus per Slack, PagerDuty, email, webhook’us. Bet svarbiausia jo funkcija – alert’ų grupavimas ir deduplication. Jei 10 serverių vienu metu praneša apie problemą, gausite vieną sugrupuotą pranešimą, ne dešimt atskirų.
Konfigūruokite routing medį pagal severity:
route:
group_by: ['alertname', 'cluster']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receiver: 'team-slack'
routes:
- match:
severity: critical
receiver: 'pagerduty'
Kritiniai alert’ai eina į PagerDuty ir žadina on-call inžinierių, kiti – į Slack kanalą, kur komanda gali reaguoti darbo valandomis.
Recording rules: kai užklausos tampa per lėtos
Kai dashboard’as turi sudėtingas PromQL užklausas, kurios skaičiuoja daugybę metrikų per ilgą laiko periodą, Grafana gali pradėti lėtėti. Recording rules išsprendžia šią problemą – jos iš anksto apskaičiuoja sudėtingas užklausas ir išsaugo rezultatus kaip naujas metrikos.
Pavyzdžiui, vietoj to, kad kiekvieną kartą skaičiuotumėte API error rate:
groups:
- name: api_metrics
interval: 30s
rules:
- record: api:error_rate:5m
expr: rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m])
Dabar dashboard’uose ir alert’uose galite tiesiog naudoti api:error_rate:5m – rezultatas bus tas pats, bet užklausa greitesnė. Pavadinimai su dvitaškiais yra konvencija – pirmoji dalis nurodo, ko metrika apie, paskutinė – laiko langą.
Kubernetes ir service discovery
Jei naudojate Kubernetes, Prometheus tampa dar galingesnis. Kubernetes service discovery automatiškai atranda pod’us, service’us, node’us ir kitus objektus. Nereikia rankiniu būdu atnaujinti target’ų sąrašo – Prometheus pats viską atranda.
Konfigūracija atrodo taip:
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
Atrodo bauginančiai, bet esmė paprasta – Prometheus ieško pod’ų su annotation prometheus.io/scrape: "true" ir scrape’ina juos. Galite nurodyti custom portą ir path per kitas annotations.
Jūsų deployment’e tiesiog pridėkite:
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
Ir viskas – Prometheus automatiškai pradės rinkti metrikos iš jūsų aplikacijos.
Kai viskas sudėta kartu: realus scenarijus
Tarkime, turite e-commerce platformą. Juodojo penktadienio išvakarėse norite būti tikri, kad viskas veiks. Štai kaip Prometheus + Grafana padeda:
Sukuriate dashboard’ą su šiais paneliais:
Traffic: Matote užklausų per sekundę grafiką. Normaliai tai 100-200 rps, bet per Black Friday tikitės 2000-3000. Jei matote tik 500, žinote, kad kažkas ne taip – galbūt load balancer’is neveikia, galbūt DNS problemos.
Latency: P50, P95, P99 percentiliai. P50 rodo tipiškam vartotojui, P99 – blogiausiam scenarijui. Jei P99 šoka nuo 200ms į 5s, turite problemą, net jei P50 atrodo gerai.
Error rate: 5xx klaidų procentas. Normaliai tai 0.01%, bet jei pakyla iki 1%, tai reiškia, kad 1 iš 100 vartotojų negauna to, ko nori. Per Black Friday tai gali būti tūkstančiai prarastų pardavimų.
Database connections: Kiek connection’ų naudojama iš pool’o. Jei artėjate prie limito, greitai pradėsite gauti „too many connections” klaidas.
Cache hit rate: Redis ar Memcached hit rate. Jei jis krenta nuo 95% į 60%, tai reiškia, kad daugiau užklausų eina į duomenų bazę, kas didina latency.
Queue depth: Jei naudojate message queue (RabbitMQ, Kafka), žiūrite, kaip greitai apdorojami message’ai. Auganti queue reiškia, kad consumer’iai nespėja.
Sukonfigūruojate alert’us:
– Error rate > 1% per 5 minutes → critical, PagerDuty
– P99 latency > 3s per 5 minutes → warning, Slack
– Database connection pool > 80% → warning, Slack
– Queue depth > 10000 → critical, PagerDuty
Black Friday dieną sėdite su komanda, žiūrite į dashboard’ą. 10:00 val. matote, kad P99 latency pradeda augti. Nėra alert’o dar, bet matote tendenciją. Paspaudžiate ant grafiko, Grafana parodo, kurie endpoint’ai lėčiausi. Pasirodo, product search API. Pažiūrite į database query time – normalus. Cache hit rate – nukritęs nuo 95% į 70%. Aha! Redis’as nebetelpa į memory, pradeda swap’inti. Greitai scale’inate Redis cluster’į, cache hit rate grįžta į normalų, latency nukrenta. Krizė išvengta dar prieš vartotojams pastebint.
Tai ne teorinis scenarijus – būtent taip Prometheus ir Grafana naudojami production aplinkose. Jie neišsprendžia problemų už jus, bet duoda informaciją, reikalingą greitam sprendimui.
Ką daryti dabar: nuo nulio iki veikiančio monitoringo
Jei skaitote iki čia ir galvojate „gerai, bet kaip pradėti?”, štai konkretus planas.
Pirmas žingsnis – paleiskite Prometheus ir Grafana lokalioje mašinoje su Docker Compose. Sukurkite docker-compose.yml:
version: '3'
services:
prometheus:
image: prom/prometheus:latest
ports:
- "9090:9090"
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana:latest
ports:
- "3000:3000"
environment:
- GF_SECURITY_ADMIN_PASSWORD=admin
Minimalus prometheus.yml:
global:
scrape_interval: 15s
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
Paleiskite docker-compose up, eikite į http://localhost:3000, prisijunkite (admin/admin), pridėkite Prometheus data source (http://prometheus:9090), importuokite dashboard’ą (ID 1860 – Node Exporter Full). Dabar turite veikiantį monitoringą.
Antras žingsnis – pridėkite node exporter prie savo serverių. Jei naudojate Ansible, Terraform ar kitą automation įrankį, tai turėtų būti standartinė dalis serverio setup’o.
Trečias žingsnis – instrumentuokite savo aplikaciją. Pradėkite nuo bazinių metrikų: užklausų skaičius, atsakymo laikas, klaidos. Naudokite Prometheus klientų bibliotekas – jos daro šį procesą paprastą.
Ketvirtas žingsnis – sukurkite pirmąjį custom dashboard’ą. Nekopijuokite kitų – sukurkite tokį, kuris atspindi jūsų sistemos specifiką. Įtraukite tik tas metrikos, kurios realiai padeda priimti sprendimus.
Penktas žingsnis – sukonfigūruokite alert’us. Pradėkite nuo akivaizdžių – serveris neatsiliepia, disk space baigiasi, error rate aukštas. Vėliau pridėsite sudėtingesnius, kai suprasite sistemos elgesį.
Šeštas žingsnis – iteruokite. Monitoringas nėra „set and forget” dalykas. Pridėkite naujas metrikos, kai pridedame naujas features. Pašalinkite metrikos, kurios niekas nežiūri. Koreguokite alert’ų thresholds pagal realų sistemos elgesį.
Ir paskutinis patarimas – nesivaržykite eksperimentuoti. Prometheus ir Grafana yra open source, galite laisvai bandyti įvairius dalykus. Sugadinote dashboard’ą? Tiesiog atkurkite iš JSON backup’o. Alert’as per daug triukšmauja? Pakoreguokite threshold’ą. Tai įrankiai, kurie turi būti pritaikyti jūsų poreikiams, ne atvirkščiai.
Monitoringas nėra tikslas savaime – tai priemonė geriau suprasti ir valdyti sistemas. Prometheus ir Grafana duoda galimybę paversti abstrakčius skaičius į suprantamą istoriją apie tai, kas vyksta jūsų infrastruktūroje. Ir kai ateis krizės momentas – o jis ateis – būsite dėkingi, kad turite šiuos įrankius po ranka.
