O ṣeese julọ, loni ko si ẹnikan ti o beere idi ti o ṣe pataki lati gba awọn metiriki iṣẹ. Igbesẹ ọgbọn ti o tẹle ni lati ṣeto itaniji fun awọn metiriki ti a gba, eyiti yoo ṣe akiyesi nipa awọn iyapa eyikeyi ninu data ninu awọn ikanni ti o rọrun fun ọ (meeli, Slack, Telegram). Ninu iṣẹ ifiṣura hotẹẹli lori ayelujara Ostrovok.ru gbogbo awọn metiriki ti awọn iṣẹ wa ni a da sinu InfluxDB ati ṣafihan ni Grafana, ati pe titaniji ipilẹ tun jẹ tunto nibẹ. Fun awọn iṣẹ ṣiṣe bii “o nilo lati ṣe iṣiro nkan kan ki o ṣe afiwe pẹlu rẹ,” a lo Kapacitor.
Kapacitor jẹ apakan ti akopọ TICK ti o le ṣe ilana awọn metiriki lati InfluxDB. O le so awọn wiwọn pupọ pọ (darapọ), ṣe iṣiro nkan ti o wulo lati data ti o gba, kọ abajade pada si InfluxDB, fi itaniji ranṣẹ si Slack/Telegram/mail.
Gbogbo akopọ jẹ itura ati alaye iwe aṣẹ, ṣugbọn awọn ohun ti o wulo nigbagbogbo yoo wa ti ko ṣe afihan ni pato ninu awọn itọnisọna. Ninu nkan yii, Mo pinnu lati gba nọmba kan ti iru iwulo, awọn imọran ti ko han gbangba (sintasi ipilẹ ti TICKscipt jẹ apejuwe nibi) kí o sì fi bí a ṣe lè fi wọ́n sílò hàn nípa lílo àpẹẹrẹ yíyanjú ọ̀kan lára àwọn ìṣòro wa.
Lọ!
leefofo & int, isiro aṣiṣe
Iṣoro idiwọn pipe, ti a yanju nipasẹ awọn simẹnti:
var alert_float = 5.0
var alert_int = 10
data|eval(lambda: float("value") > alert_float OR float("value") < float("alert_int"))
Nipa aiyipada, darapọ mọ awọn aaye ti ko si data (inu).
Nigbati o ba kun ('asan') isọdọkan ita yoo ṣee ṣe, lẹhin eyi o nilo lati ṣe aiyipada () ki o kun awọn iye ofo:
var data = res1
|join(res2)
.as('res1', 'res2)
.fill('null')
|default()
.field('res1.value', 0.0)
.field('res2.value', 100.0)
Nuance tun wa nibi. Ninu apẹẹrẹ ti o wa loke, ti ọkan ninu jara (res1 tabi res2) ba ṣofo, jara ti abajade (data) yoo tun jẹ ofo. Awọn tikẹti pupọ wa lori koko yii lori Github (1633, 1871, 6967) - a n duro de awọn atunṣe ati ijiya diẹ.
Lilo awọn ipo ni iṣiro (ti o ba wa ni lambda)
|eval(lambda: if("value" > 0, true, false)
Iṣẹju marun to kẹhin lati opo gigun ti epo fun akoko naa
Fun apẹẹrẹ, o nilo lati ṣe afiwe awọn iye ti iṣẹju marun to kẹhin pẹlu ọsẹ ti tẹlẹ. O le gba awọn ipele meji ti data ni awọn ipele lọtọ meji tabi yọ apakan ti data jade lati akoko nla:
Yiyan fun iṣẹju marun to kẹhin yoo jẹ lati lo BarrierNode kan, eyiti o ge data kuro ṣaaju akoko ti a sọ pato:
|barrier()
.period(5m)
Awọn apẹẹrẹ ti lilo awọn awoṣe Go ninu ifiranṣẹ
Awọn awoṣe badọgba si ọna kika lati package ọrọ.awoṣeNi isalẹ wa diẹ ninu awọn adojuru ti o nwaye nigbagbogbo.
ti o ba ti-miiran
A ṣeto awọn nkan ati pe a ko ṣe okunfa eniyan pẹlu ọrọ lẹẹkan si:
|alert()
...
.message(
'{{ if eq .Level "OK" }}It is ok now{{ else }}Chief, everything is broken{{end}}'
)
Awọn nọmba meji lẹhin aaye eleemewa ninu ifiranṣẹ
Imudara kika ti ifiranṣẹ naa:
|alert()
...
.message(
'now value is {{ index .Fields "value" | printf "%0.2f" }}'
)
Faagun awọn oniyipada ninu ifiranṣẹ
A ṣe afihan alaye diẹ sii ninu ifiranṣẹ lati dahun ibeere naa “Kini idi ti o n pariwo”?
var warnAlert = 10
|alert()
...
.message(
'Today value less then '+string(warnAlert)+'%'
)
Oto gbigbọn idamo
Eyi jẹ ohun pataki nigbati o ba wa ju ẹgbẹ kan lọ ninu data naa, bibẹẹkọ titaniji kan yoo jẹ ipilẹṣẹ:
|alert()
...
.id('{{ index .Tags "myname" }}/{{ index .Tags "myfield" }}')
Aṣa olutọju ká
Atokọ nla ti awọn olutọju pẹlu exec, eyiti o fun ọ laaye lati ṣiṣẹ iwe afọwọkọ rẹ pẹlu awọn aye ti o kọja (stdin) - iṣẹda ati ohunkohun diẹ sii!
Ọkan ninu awọn aṣa wa jẹ iwe afọwọkọ Python kekere kan fun fifiranṣẹ awọn iwifunni si ọlẹ.
Ni akọkọ, a fẹ lati firanṣẹ aworan grafana ti o ni aabo ni aṣẹ ninu ifiranṣẹ kan. Lẹhinna, kọ O dara ninu o tẹle ara si titaniji iṣaaju lati ẹgbẹ kanna, kii ṣe bi ifiranṣẹ lọtọ. Ni igba diẹ - ṣafikun ifiranṣẹ aṣiṣe ti o wọpọ julọ ni awọn iṣẹju X to kẹhin.
Koko lọtọ jẹ ibaraẹnisọrọ pẹlu awọn iṣẹ miiran ati awọn iṣe eyikeyi ti o bẹrẹ nipasẹ itaniji (nikan ti ibojuwo rẹ ba ṣiṣẹ daradara to).
Apeere ti apejuwe olutọju kan, nibiti slack_handler.py jẹ iwe afọwọkọ ti ara wa:
Fun apẹẹrẹ, a ṣeto itaniji fun apao awọn ibeere fun wakati kan (ẹgbẹBy(1h)) ati pe a fẹ lati ṣe igbasilẹ titaniji ti o waye ni influxdb (lati fi ẹwa han otitọ iṣoro naa lori aworan ni grafana).
influxDBout () yoo kọ iye akoko lati gbigbọn si timestamp; ni ibamu, aaye ti o wa lori chart yoo kọ tẹlẹ / nigbamii ju gbigbọn ti de.
Nigbati o ba nilo deede: a ṣiṣẹ ni ayika iṣoro yii nipa pipe oluṣakoso aṣa, eyiti yoo kọ data si influxdb pẹlu aami akoko lọwọlọwọ.
docker, kọ ati imuṣiṣẹ
Ni ibẹrẹ, kapacitor le gbe awọn iṣẹ-ṣiṣe, awọn awoṣe ati awọn olutọju lati inu iwe-itọsọna ti a pato ninu iṣeto ni [fifuye] Àkọsílẹ.
Lati ṣẹda iṣẹ-ṣiṣe ti o tọ, o nilo awọn nkan wọnyi:
Orukọ faili – gbooro si id/orukọ iwe afọwọkọ
Iru - ṣiṣan / ipele
dbrp – Koko lati tọka iru data + eto imulo ti iwe afọwọkọ nṣiṣẹ ninu (dbrp “olupese.” “autogen”)
Ti iṣẹ-ṣiṣe ipele kan ko ba ni laini pẹlu dbrp, gbogbo iṣẹ naa yoo kọ lati bẹrẹ ati pe yoo kọ nipa rẹ ni otitọ ninu akọọlẹ.
Ni chronograf, ni ilodi si, laini yii ko yẹ ki o wa; ko gba nipasẹ wiwo ati ṣe ipilẹṣẹ aṣiṣe.
Gige nigbati o ba n kọ eiyan kan: Dockerfile jade pẹlu -1 ti awọn laini ba wa pẹlu //.+dbrp, eyiti yoo gba ọ laaye lati loye lẹsẹkẹsẹ idi fun ikuna nigbati o ba n pejọ kọ.
darapọ mọ ọkan si ọpọlọpọ
Apẹẹrẹ iṣẹ-ṣiṣe: o nilo lati mu ipin 95th ti akoko iṣẹ iṣẹ fun ọsẹ kan, ṣe afiwe iṣẹju kọọkan ti 10 to kẹhin pẹlu iye yii.
O ko le ṣe idapọ ọkan-si-ọpọlọpọ, kẹhin / tumosi / agbedemeji lori ẹgbẹ kan ti awọn aaye yi oju ipade sinu ṣiṣan, aṣiṣe “ko le ṣafikun awọn egbegbe ti ko baamu ọmọ: ipele -> ṣiṣan” yoo pada.
Abajade ipele kan, bi oniyipada ninu ikosile lambda, ko tun paarọ rẹ.
Aṣayan wa lati ṣafipamọ awọn nọmba pataki lati ipele akọkọ si faili nipasẹ udf ati fifuye faili yii nipasẹ fifuye ẹgbẹ.
Kini a yanju pẹlu eyi?
A ni awọn olupese hotẹẹli to bii 100, ọkọọkan wọn le ni awọn asopọ pupọ, jẹ ki a pe ni ikanni kan. O fẹrẹ to 300 ti awọn ikanni wọnyi, ọkọọkan awọn ikanni le ṣubu ni pipa. Ninu gbogbo awọn metiriki ti o gbasilẹ, a yoo ṣe atẹle oṣuwọn aṣiṣe (awọn ibeere ati awọn aṣiṣe).
Kilode ti kii ṣe grafana?
Awọn titaniji aṣiṣe ni tunto ni Grafana ni ọpọlọpọ awọn alailanfani. Diẹ ninu jẹ pataki, diẹ ninu awọn ti o le pa oju rẹ si, da lori ipo naa.
Grafana ko mọ bi o ṣe le ṣe iṣiro laarin awọn wiwọn + titaniji, ṣugbọn a nilo oṣuwọn kan (awọn ibeere-aṣiṣe)/awọn ibeere.
Awọn aṣiṣe dabi buburu:
Ati pe o kere si ibi nigba wiwo pẹlu awọn ibeere aṣeyọri:
O dara, a le ṣaju-iṣiro oṣuwọn ninu iṣẹ ṣaaju grafana, ati ni awọn igba miiran eyi yoo ṣiṣẹ. Ṣugbọn kii ṣe ninu tiwa, nitori ... fun ikanni kọọkan ni ipin tirẹ ni “deede”, ati awọn itaniji ṣiṣẹ ni ibamu si awọn iye aimi (a wa wọn pẹlu oju wa, yi wọn pada ti awọn itaniji loorekoore ba wa).
Iwọnyi jẹ apẹẹrẹ ti “deede” fun awọn ikanni oriṣiriṣi:
A foju aaye ti tẹlẹ ati ro pe aworan “deede” jẹ iru fun gbogbo awọn olupese. Bayi ohun gbogbo dara, ati pe a le gba pẹlu awọn titaniji ni grafana?
A le, ṣugbọn a ko fẹ gaan, nitori a ni lati yan ọkan ninu awọn aṣayan:
a) ṣe ọpọlọpọ awọn aworan fun ikanni kọọkan lọtọ (ati ni irora tẹle wọn)
b) fi apẹrẹ kan silẹ pẹlu gbogbo awọn ikanni (ki o padanu ni awọn laini awọ ati awọn itaniji ti adani)
dbrp "supplier"."autogen"
var name = 'requests.rate'
var grafana_dash = 'pczpmYZWU/mydashboard'
var grafana_panel = '26'
var period = 8h
var todayPeriod = 10m
var every = 1m
var warnAlert = 15
var warnReset = 5
var reqQuery = 'SELECT sum("count") AS value FROM "supplier"."autogen"."requests"'
var errQuery = 'SELECT sum("count") AS value FROM "supplier"."autogen"."errors"'
var prevErr = batch
|query(errQuery)
.period(period)
.every(every)
.groupBy(1m, 'channel', 'supplier')
var prevReq = batch
|query(reqQuery)
.period(period)
.every(every)
.groupBy(1m, 'channel', 'supplier')
var rates = prevReq
|join(prevErr)
.as('req', 'err')
.tolerance(1m)
.fill('null')
// заполняем значения нулями, если их не было
|default()
.field('err.value', 0.0)
.field('req.value', 0.0)
// if в lambda: считаем рейт, только если ошибки были
|eval(lambda: if("err.value" > 0, 100.0 * (float("req.value") - float("err.value")) / float("req.value"), 100.0))
.as('rate')
// записываем посчитанные значения в инфлюкс
rates
|influxDBOut()
.quiet()
.create()
.database('kapacitor')
.retentionPolicy('autogen')
.measurement('rates')
// выбираем данные за последние 10 минут, считаем медиану
var todayRate = rates
|where(lambda: duration((unixNano(now()) - unixNano("time")) / 1000, 1u) < todayPeriod)
|median('rate')
.as('median')
var prevRate = rates
|median('rate')
.as('median')
var joined = todayRate
|join(prevRate)
.as('today', 'prev')
|httpOut('join')
var trigger = joined
|alert()
.warn(lambda: ("prev.median" - "today.median") > warnAlert)
.warnReset(lambda: ("prev.median" - "today.median") < warnReset)
.flapping(0.25, 0.5)
.stateChangesOnly()
// собираем в message ссылку на график дашборда графаны
.message(
'{{ .Level }}: {{ index .Tags "channel" }} err/req ratio ({{ index .Tags "supplier" }})
{{ if eq .Level "OK" }}It is ok now{{ else }}
'+string(todayPeriod)+' median is {{ index .Fields "today.median" | printf "%0.2f" }}%, by previous '+string(period)+' is {{ index .Fields "prev.median" | printf "%0.2f" }}%{{ end }}
http://grafana.ostrovok.in/d/'+string(grafana_dash)+
'?var-supplier={{ index .Tags "supplier" }}&var-channel={{ index .Tags "channel" }}&panelId='+string(grafana_panel)+'&fullscreen&tz=UTC%2B03%3A00'
)
.id('{{ index .Tags "name" }}/{{ index .Tags "channel" }}')
.levelTag('level')
.messageField('message')
.durationField('duration')
.topic('slack_graph')
// "today.median" дублируем как "value", также пишем в инфлюкс остальные филды алерта (keep)
trigger
|eval(lambda: "today.median")
.as('value')
.keep()
|influxDBOut()
.quiet()
.create()
.database('kapacitor')
.retentionPolicy('autogen')
.measurement('alerts')
.tag('alertName', name)
Kini ipari?
Kapacitor jẹ nla ni ṣiṣe awọn titaniji ibojuwo pẹlu akojọpọ awọn akojọpọ, ṣiṣe awọn iṣiro afikun ti o da lori awọn metiriki ti o ti gbasilẹ tẹlẹ, ṣiṣe awọn iṣe aṣa ati awọn iwe afọwọkọ nṣiṣẹ (udf).
Idanwo si titẹsi ko ga pupọ - gbiyanju rẹ ti grafana tabi awọn irinṣẹ miiran ko ni itẹlọrun awọn ifẹ rẹ ni kikun.