Probabbilment, illum ħadd ma jistaqsi għaliex huwa meħtieġ li jinġabru metriċi tas-servizz. Il-pass loġiku li jmiss huwa li twaqqaf twissija għall-metriċi miġbura, li tinnotifika dwar kwalunkwe devjazzjoni fid-dejta f'kanali konvenjenti għalik (posta, Slack, Telegramma). Fis-servizz online tal-prenotazzjoni tal-lukandi il-metriċi kollha tas-servizzi tagħna jitferra 'f'InfluxDB u jintwerew fi Grafana, u hemm ukoll ikkonfigurat twissija bażika. Għal kompiti bħal "għandek bżonn tikkalkula xi ħaġa u tqabbel magħha," nużaw Kapacitor.

Kapacitor huwa parti mill-munzell TICK li jista 'jipproċessa metriċi minn InfluxDB. Jista 'jgħaqqad diversi kejl flimkien (jingħaqad), jikkalkula xi ħaġa utli mid-dejta riċevuta, jikteb ir-riżultat lura lil InfluxDB, jibgħat twissija lil Slack/Telegram/mail.
Il-munzell kollu huwa frisk u dettaljat , iżda dejjem se jkun hemm affarijiet utli li mhumiex indikati b'mod espliċitu fil-manwali. F'dan l-artikolu, iddeċidejt li niġbor għadd ta' suġġerimenti utli u mhux ovvji bħal dawn (is-sintassi bażika ta' TICKscipt hija deskritta ) u juru kif jistgħu jiġu applikati bl-użu ta’ eżempju ta’ kif insolvu waħda mill-problemi tagħna.
Ejja ħa mmorru!
float & int, żbalji fil-kalkolu
Problema assolutament standard, solvuta permezz ta’ kasti:
var alert_float = 5.0
var alert_int = 10
data|eval(lambda: float("value") > alert_float OR float("value") < float("alert_int"))
Bl-użu default()
Jekk tikketta/field ma jimtlewx, se jseħħu żbalji fil-kalkolu:
|default()
.tag('status', 'empty')
.field('value', 0)
imla jingħaqad (ġewwa vs barra)
B'mod awtomatiku, join se jarmi l-punti fejn m'hemm l-ebda data (interjuri).
Bil-fill('null'), se titwettaq jewter join, u wara trid tagħmel default() u timla l-valuri vojta:
var data = res1
|join(res2)
.as('res1', 'res2)
.fill('null')
|default()
.field('res1.value', 0.0)
.field('res2.value', 100.0)
Għad hemm sfumatura hawn. Fl-eżempju ta 'hawn fuq, jekk waħda mis-serje (res1 jew res2) tkun vojta, is-serje li tirriżulta (data) tkun vojta wkoll. Hemm diversi biljetti fuq dan is-suġġett fuq Github (, , ) – qed nistennew irranġati u tbatija ftit.
L-użu tal-kundizzjonijiet fil-kalkoli (jekk f'lambda)
|eval(lambda: if("value" > 0, true, false)
L-aħħar ħames minuti mill-pipeline għall-perjodu
Pereżempju, trid tqabbel il-valuri tal-aħħar ħames minuti mal-ġimgħa ta 'qabel. Tista' tieħu żewġ lottijiet ta' dejta f'żewġ lottijiet separati jew estratti parti mid-dejta minn perjodu akbar:
|where(lambda: duration((unixNano(now()) - unixNano("time"))/1000, 1u) < 5m)
Alternattiva għall-aħħar ħames minuti tkun li tuża BarrierNode, li jaqta 'data qabel il-ħin speċifikat:
|barrier()
.period(5m)
Eżempji tal-użu tal-mudelli Go fil-messaġġ
Il-mudelli jikkorrispondu mal-format mill-pakkett Hawn taħt hawn xi puzzles li jiltaqgħu magħhom spiss.
jekk-inkella
Aħna npoġġu l-affarijiet fl-ordni u ma nixprunawx lin-nies bit-test għal darb'oħra:
|alert()
...
.message(
'{{ if eq .Level "OK" }}It is ok now{{ else }}Chief, everything is broken{{end}}'
)
Żewġ ċifri wara l-punt deċimali fil-messaġġ
Titjib tal-leġibbiltà tal-messaġġ:
|alert()
...
.message(
'now value is {{ index .Fields "value" | printf "%0.2f" }}'
)
Espansjoni varjabbli fil-messaġġ
Aħna nuru aktar informazzjoni fil-messaġġ biex inwieġbu l-mistoqsija "Għaliex qed tgħajjat"?
var warnAlert = 10
|alert()
...
.message(
'Today value less then '+string(warnAlert)+'%'
)
Identifikatur uniku ta' twissija
Din hija ħaġa neċessarja meta jkun hemm aktar minn grupp wieħed fid-dejta, inkella se tiġi ġġenerata twissija waħda biss:
|alert()
...
.id('{{ index .Tags "myname" }}/{{ index .Tags "myfield" }}')
Custom handler's
Il-lista kbira ta 'handlers tinkludi exec, li jippermettilek tesegwixxi l-iskrittura tiegħek bil-parametri mgħoddija (stdin) - kreattività u xejn aktar!
Waħda mid-dwana tagħna hija script Python żgħir biex jintbagħtu notifiki lil slack.
Għall-ewwel, ridna nibagħtu stampa grafana protetta minn awtorizzazzjoni f'messaġġ. Wara, ikteb OK fil-ħajt għat-twissija preċedenti mill-istess grupp, u mhux bħala messaġġ separat. Ftit aktar tard - żid mal-messaġġ l-iżball l-aktar komuni fl-aħħar X minuti.
Suġġett separat huwa l-komunikazzjoni ma’ servizzi oħra u kwalunkwe azzjoni mibdija minn twissija (biss jekk il-monitoraġġ tiegħek jaħdem tajjeb biżżejjed).
Eżempju ta' deskrizzjoni ta' handler, fejn slack_handler.py huwa l-iskrittura miktuba minnha nfisha:
topic: slack_graph
id: slack_graph.alert
match: level() != INFO AND changed() == TRUE
kind: exec
options:
prog: /sbin/slack_handler.py
args: ["-c", "CHANNELID", "--graph", "--search"]
Kif tiddibaggja?
Għażla b'output ta 'log
|log()
.level("error")
.prefix("something")
Watch (cli): kapacitor -url :9092 logs lvl=żball
Għażla ma httpOut
Juri dejta fil-pipeline attwali:
|httpOut('something')
Watch (ikseb): :9092/kapacitor/v1/tasks/task_name/xi ħaġa
Dijagramma ta' eżekuzzjoni
- Kull kompitu jirritorna siġra tal-eżekuzzjoni b'numri utli fil-format .
- Ħu blokk .
- Pasteha fit-telespettatur, .
Fejn inkella tista 'tikseb rake?
timestamp fl-influxdb fuq writeback
Per eżempju, aħna waqqafna twissija għas-somma ta 'talbiet għal kull siegħa (groupBy(1h)) u rridu nirreġistraw it-twissija li seħħet fl-influxdb (biex turi b'mod sabiħ il-fatt tal-problema fuq il-grafika f'grafana).
influxDBOut() se jikteb il-valur tal-ħin mit-twissija sal-timestamp kif xieraq, il-punt fuq iċ-ċart se jinkiteb qabel/aktar tard milli waslet it-twissija;
Meta tkun meħtieġa l-eżattezza: naħdmu madwar din il-problema billi nsejħu lil handler tad-dwana, li jikteb id-dejta lil influxdb bit-timestamp attwali.
docker, bini u skjerament
Fl-istartjar, kapacitor jista' jgħabbi kompiti, mudelli u handlers mid-direttorju speċifikat fil-konfigurazzjoni fil-blokk [load].
Biex toħloq kompitu b'mod korrett, għandek bżonn l-affarijiet li ġejjin:
- Isem tal-fajl - estiż f'id/isem tal-iskript
- Tip – fluss/lott
- dbrp – keyword biex tindika liema database + politika taħdem fiha l-iscript (dbrp “fornitur.” “autogen”)
Jekk xi kompitu tal-lott ma jkunx fih linja b'dbrp, is-servizz kollu jirrifjuta li jibda u jikteb dwaru b'mod onest fir-reġistru.
Fil-chronograf, għall-kuntrarju, din il-linja m'għandhiex teżisti ma tkunx aċċettata permezz tal-interface u tiġġenera żball;
Hack meta tibni kontenitur: Dockerfile joħroġ b'-1 jekk ikun hemm linji b' //.+dbrp, li jippermettilek tifhem immedjatament ir-raġuni għall-falliment meta tgħaqqad il-bini.
tingħaqad wieħed għal ħafna
Eżempju ta' ħidma: trid tieħu l-95 perċentil tal-ħin operattiv tas-servizz għal ġimgħa, qabbel kull minuta tal-aħħar 10 ma' dan il-valur.
Ma tistax tagħmel wieħed għal ħafna jingħaqdu, l-aħħar/medja/medjan fuq grupp ta 'punti ddawwar in-nodu fi fluss, l-iżball "ma tistax iżżid truf mhux imqabbla tat-tfal: lott -> fluss" se jiġi rritornat.
Ir-riżultat ta' lott, bħala varjabbli f'espressjoni lambda, lanqas ma jiġi sostitwit.
Hemm għażla li tissejvja n-numri meħtieġa mill-ewwel lott għal fajl permezz ta 'udf u tagħbija dan il-fajl permezz ta' sideload.
X’solvejna b’dan?
Għandna madwar 100 fornitur tal-lukandi, kull wieħed minnhom jista 'jkollu diversi konnessjonijiet, ejja nsejħulha kanal. Hemm madwar 300 minn dawn il-kanali, kull wieħed mill-kanali jista 'jaqa'. Mill-metriċi kollha rreġistrati, aħna se nissorveljaw ir-rata ta 'żball (talbiet u żbalji).
Għaliex ma grafana?
Twissijiet ta 'żbalji kkonfigurati fi Grafana għandhom diversi żvantaġġi. Xi wħud huma kritiċi, xi wħud tista 'tagħlaq għajnejk għalihom, skond is-sitwazzjoni.
Grafana ma jafx kif tikkalkula bejn kejl + twissija, iżda għandna bżonn rata (talbiet-iżbalji)/talbiet.
L-iżbalji jidhru diżgustanti:

U inqas ħażen meta wieħed iħares lejn talbiet b'suċċess:

Okay, nistgħu nikkalkulaw minn qabel ir-rata fis-servizz qabel il-grafana, u f'xi każijiet dan jaħdem. Imma mhux tagħna, għax... għal kull kanal il-proporzjon tiegħu huwa meqjus bħala "normali", u t-twissijiet jaħdmu skont valuri statiċi (aħna nħarsu b'għajnejna, nibdlu jekk ikun hemm twissijiet frekwenti).
Dawn huma eżempji ta '"normali" għal kanali differenti:


Aħna ninjoraw il-punt preċedenti u nassumu li l-istampa "normali" hija simili għall-fornituri kollha. Issa kollox sew, u nistghu nghaddu b'allerti fil-grafana?
Nistgħu, imma verament ma rridux, għax irridu nagħżlu waħda mill-għażliet:
a) agħmel ħafna graphs għal kull kanal separatament (u akkumpanjahom bi tbatija)
b) ħalli chart waħda bil-kanali kollha (u tintilef fil-linji mlewna u twissijiet personalizzati)

Kif għamiltu?
Għal darb'oħra, hemm eżempju tajjeb tal-bidu fid-dokumentazzjoni (), jistgħu jiġu ħarsa lejn jew jittieħdu bħala bażi fi problemi simili.
Dak li għamilna fl-aħħar:
- tingħaqad ma 'żewġ serje fi ftit sigħat, raggruppament mill-kanali;
- imla s-serje skond il-grupp jekk ma kienx hemm dejta;
- qabbel il-medjan tal-aħħar 10 minuti mad-dejta preċedenti;
- ngħajtu jekk insibu xi ħaġa;
- niktbu r-rati kkalkulati u t-twissijiet li seħħew fl-influxdb;
- ibgħat messaġġ utli lil slack.
Fl-opinjoni tiegħi, irnexxielna niksbu dak kollu li ridna niksbu fl-aħħar (u anke ftit aktar bi custom handlers) bl-aħjar mod possibbli.
Tista' tħares lejn github.com и l-iskrittura li tirriżulta.
Eżempju tal-kodiċi li jirriżulta:
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)
X'inhi l-konklużjoni?
Kapacitor huwa kbir biex iwettaq monitoraġġ-allerti ma 'mazz ta' gruppi, iwettaq kalkoli addizzjonali bbażati fuq metriċi diġà rreġistrati, iwettaq azzjonijiet personalizzati u jmexxi skripts (udf).
L-ostaklu għad-dħul mhuwiex għoli ħafna - ipprova jekk il-grafana jew għodda oħra ma jissodisfawx bis-sħiħ ix-xewqat tiegħek.
Sors: www.habr.com
