Yn fwyaf tebygol, heddiw does neb yn gofyn pam mae angen casglu metrigau gwasanaeth. Y cam rhesymegol nesaf yw sefydlu rhybudd ar gyfer y metrigau a gasglwyd, a fydd yn hysbysu am unrhyw wyriadau yn y data mewn sianeli sy'n gyfleus i chi (post, Slack, Telegram). Yn y gwasanaeth archebu gwesty ar-lein Ostrovok.ru mae holl fetrigau ein gwasanaethau yn cael eu tywallt i InfluxDB a'u harddangos yn Grafana, ac mae rhybuddion sylfaenol hefyd wedi'u ffurfweddu yno. Ar gyfer tasgau fel “mae angen i chi gyfrifo rhywbeth a'i gymharu ag ef,” rydyn ni'n defnyddio Kapacitor.
Mae Kapacitor yn rhan o'r stack TICK sy'n gallu prosesu metrigau o InfluxDB. Gall gysylltu sawl mesuriad gyda'i gilydd (ymuno), cyfrifo rhywbeth defnyddiol o'r data a dderbyniwyd, ysgrifennu'r canlyniad yn ôl i InfluxDB, anfon rhybudd i Slack / Telegram / post.
Mae'r pentwr cyfan yn oer ac yn fanwl dogfennaeth, ond bydd pethau defnyddiol bob amser nad ydynt wedi'u nodi'n benodol yn y llawlyfrau. Yn yr erthygl hon, penderfynais gasglu nifer o awgrymiadau defnyddiol, nad ydynt yn amlwg (disgrifir cystrawen sylfaenol TICKscipt yma) a dangos sut y gellir eu cymhwyso gan ddefnyddio enghraifft o ddatrys un o'n problemau.
Gadewch i ni fynd!
arnofio & int, gwallau cyfrifo
Problem hollol safonol, wedi'i datrys trwy gastiau:
var alert_float = 5.0
var alert_int = 10
data|eval(lambda: float("value") > alert_float OR float("value") < float("alert_int"))
Defnyddio rhagosodedig()
Os na chaiff tag/maes ei lenwi, bydd gwallau cyfrifo yn digwydd:
Yn ddiofyn, bydd ymuno yn taflu pwyntiau lle nad oes data (mewnol).
Gyda llenwi ('null'), bydd uniad allanol yn cael ei berfformio, ac ar ôl hynny mae angen i chi wneud rhagosodiad() a llenwi'r gwerthoedd gwag:
var data = res1
|join(res2)
.as('res1', 'res2)
.fill('null')
|default()
.field('res1.value', 0.0)
.field('res2.value', 100.0)
Mae naws yma o hyd. Yn yr enghraifft uchod, os yw un o'r gyfres (res1 neu res2) yn wag, bydd y gyfres canlyniadol (data) hefyd yn wag. Mae sawl tocyn ar y pwnc hwn ar Github (1633, 1871, 6967) – rydym yn aros am atebion ac yn dioddef ychydig.
Defnyddio amodau mewn cyfrifiadau (os yw mewn lambda)
|eval(lambda: if("value" > 0, true, false)
Pum munud olaf o'r gweill ar gyfer y cyfnod
Er enghraifft, mae angen i chi gymharu gwerthoedd y pum munud diwethaf â'r wythnos flaenorol. Gallwch gymryd dau swp o ddata mewn dau swp ar wahân neu dynnu rhan o'r data o gyfnod mwy:
Dewis arall ar gyfer y pum munud olaf fyddai defnyddio BarrierNode, sy'n torri data cyn yr amser penodedig:
|barrier()
.period(5m)
Enghreifftiau o ddefnyddio templedi Go mewn neges
Mae templedi yn cyfateb i fformat y pecyn testun.templedIsod mae rhai posau y deuir ar eu traws yn aml.
os-arall
Rydyn ni'n rhoi pethau mewn trefn ac nid ydyn ni'n sbarduno pobl â thestun unwaith eto:
|alert()
...
.message(
'{{ if eq .Level "OK" }}It is ok now{{ else }}Chief, everything is broken{{end}}'
)
Dau ddigid ar ôl y pwynt degol yn y neges
Gwella darllenadwyedd y neges:
|alert()
...
.message(
'now value is {{ index .Fields "value" | printf "%0.2f" }}'
)
Ehangu newidynnau yn y neges
Rydym yn dangos mwy o wybodaeth yn y neges i ateb y cwestiwn “Pam ei fod yn gweiddi”?
var warnAlert = 10
|alert()
...
.message(
'Today value less then '+string(warnAlert)+'%'
)
Dynodydd rhybudd unigryw
Mae hyn yn angenrheidiol pan fo mwy nag un grŵp yn y data, fel arall dim ond un rhybudd a gynhyrchir:
|alert()
...
.id('{{ index .Tags "myname" }}/{{ index .Tags "myfield" }}')
Triniwr personol
Mae'r rhestr fawr o drinwyr yn cynnwys exec, sy'n eich galluogi i weithredu'ch sgript gyda'r paramedrau a basiwyd (stdin) - creadigrwydd a dim byd mwy!
Un o'n harferion yw sgript Python bach ar gyfer anfon hysbysiadau i slac.
Ar y dechrau, roeddem am anfon llun grafana wedi'i ddiogelu gan awdurdodiad mewn neges. Wedi hynny, ysgrifennwch Iawn yn yr edefyn i'r rhybudd blaenorol o'r un grŵp, ac nid fel neges ar wahân. Ychydig yn ddiweddarach - ychwanegu at y neges y camgymeriad mwyaf cyffredin yn yr X munud olaf.
Pwnc ar wahân yw cyfathrebu â gwasanaethau eraill ac unrhyw gamau a ysgogir gan rybudd (dim ond os yw'ch monitro'n gweithio'n ddigon da).
Enghraifft o ddisgrifiad triniwr, lle mae slack_handler.py yn ein sgript hunan-ysgrifenedig:
Er enghraifft, rydym yn gosod rhybudd ar gyfer swm y ceisiadau yr awr (groupBy(1h)) ac rydym am gofnodi'r rhybudd a ddigwyddodd mewn influxdb (i ddangos yn hyfryd ffaith y broblem ar y graff mewn grafana).
bydd influxDBOut() yn ysgrifennu'r gwerth amser o'r rhybudd i'r stamp amser; yn unol â hynny, bydd y pwynt ar y siart yn cael ei ysgrifennu yn gynharach/yn hwyrach nag y cyrhaeddodd y rhybudd.
Pan fo angen cywirdeb: rydym yn gweithio o gwmpas y broblem hon trwy ffonio triniwr arfer, a fydd yn ysgrifennu data i influxdb gyda'r stamp amser cyfredol.
docwr, adeiladu a lleoli
Wrth gychwyn, gall kapacitor lwytho tasgau, templedi a thrinwyr o'r cyfeiriadur a nodir yn y ffurfwedd yn y bloc [load].
I greu tasg yn gywir, mae angen y pethau canlynol arnoch:
Enw ffeil - wedi'i ehangu i ID/enw'r sgript
Math – ffrwd/swp
dbrp - allweddair i nodi ym mha gronfa ddata + polisi mae'r sgript yn rhedeg (dbrp “cyflenwr.” “autogen”)
Os nad yw rhyw dasg swp yn cynnwys llinell â dbrp, bydd y gwasanaeth cyfan yn gwrthod cychwyn a bydd yn ysgrifennu amdano yn onest yn y log.
Yn chronograf, i'r gwrthwyneb, ni ddylai'r llinell hon fodoli; ni chaiff ei dderbyn trwy'r rhyngwyneb ac mae'n cynhyrchu gwall.
Haciwch wrth adeiladu cynhwysydd: Mae Dockerfile yn gadael gyda -1 os oes llinellau gyda //.+dbrp, a fydd yn caniatáu ichi ddeall ar unwaith y rheswm dros y methiant wrth gydosod yr adeiladwaith.
ymuno un i lawer
Tasg enghreifftiol: mae angen i chi gymryd y 95fed canradd o amser gweithredu'r gwasanaeth am wythnos, cymharwch bob munud o'r 10 olaf gyda'r gwerth hwn.
Ni allwch wneud uniad un-i-lawer, mae olaf / cymedrig / canolrif dros grŵp o bwyntiau yn troi'r nod yn nant, bydd y gwall "methu ychwanegu ymylon camgyfatebol plentyn: swp -> ffrwd" yn cael ei ddychwelyd.
Nid yw canlyniad swp, fel newidyn mewn mynegiant lambda, yn cael ei ddisodli ychwaith.
Mae opsiwn i arbed y niferoedd angenrheidiol o'r swp cyntaf i ffeil trwy UDF a llwytho'r ffeil hon trwy sideload.
Beth wnaethon ni ei ddatrys gyda hyn?
Mae gennym tua 100 o gyflenwyr gwesty, gall pob un ohonynt gael nifer o gysylltiadau, gadewch i ni ei alw'n sianel. Mae tua 300 o'r sianeli hyn, gall pob un o'r sianeli ddisgyn i ffwrdd. O'r holl fetrigau a gofnodwyd, byddwn yn monitro'r gyfradd gwallau (ceisiadau a gwallau).
Beth am grafana?
Mae sawl anfantais i rybuddion gwall sydd wedi'u ffurfweddu yn Grafana. Mae rhai yn hollbwysig, rhai y gallwch chi gau eich llygaid iddyn nhw, yn dibynnu ar y sefyllfa.
Nid yw Grafana yn gwybod sut i gyfrifo rhwng mesuriadau + rhybuddio, ond mae angen cyfradd (ceisiadau-gwallau)/ceisiadau arnom.
Mae'r gwallau'n edrych yn gas:
A llai o ddrwg pan edrychir arno gyda cheisiadau llwyddiannus:
Iawn, gallwn rag-gyfrifo'r gyfradd yn y gwasanaeth cyn grafana, ac mewn rhai achosion bydd hyn yn gweithio. Ond nid yn ein un ni, oherwydd ... ar gyfer pob sianel mae ei gymhareb ei hun yn cael ei hystyried yn “normal”, ac mae rhybuddion yn gweithio yn ôl gwerthoedd statig (rydym yn edrych gyda'n llygaid, yn newid os oes rhybuddion aml).
Dyma enghreifftiau o “normal” ar gyfer gwahanol sianeli:
Anwybyddwn y pwynt blaenorol a thybiwn fod y darlun “normal” yn debyg i bob cyflenwr. Nawr mae popeth yn iawn, a gallwn ni fynd heibio gyda rhybuddion mewn grafana?
Gallwn, ond nid ydym wir eisiau gwneud hynny, oherwydd mae'n rhaid i ni ddewis un o'r opsiynau:
a) gwneud llawer o graffiau ar gyfer pob sianel ar wahân (a mynd gyda nhw yn boenus)
b) gadael un siart gyda phob sianel (a mynd ar goll yn y llinellau lliwgar a'r rhybuddion wedi'u haddasu)
ymuno â dwy gyfres mewn ychydig oriau, gan grwpio yn ôl sianeli;
llenwi'r gyfres fesul grŵp os nad oedd data;
cymharu canolrif y 10 munud diwethaf â data blaenorol;
bloeddiwn os canfyddwn rywbeth;
rydym yn ysgrifennu'r cyfraddau a'r rhybuddion a gyfrifwyd a ddigwyddodd mewn mewnlifiad;
anfon neges ddefnyddiol i slac.
Yn fy marn i, fe wnaethom lwyddo i gyflawni popeth yr oeddem am ei gael ar y diwedd (a hyd yn oed ychydig yn fwy gyda thrinwyr arfer) mor hyfryd â phosibl.
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)
Beth yw'r casgliad?
Mae Kapacitor yn wych am berfformio rhybuddion monitro gyda chriw o grwpiau, perfformio cyfrifiadau ychwanegol yn seiliedig ar fetrigau a gofnodwyd eisoes, perfformio gweithredoedd arfer a rhedeg sgriptiau (udf).
Nid yw'r rhwystr rhag mynediad yn uchel iawn - rhowch gynnig arni os nad yw grafana neu offer eraill yn bodloni'ch dymuniadau'n llawn.