Triciau ar gyfer prosesu metrigau yn Kapacitor

Mae'n debyg nad oes neb yn pendroni mwyach pam ei bod hi'n angenrheidiol casglu metrigau gwasanaeth. Y cam rhesymegol nesaf yw sefydlu rhybuddion ar gyfer y metrigau a gesglir, a fydd yn eich hysbysu o unrhyw wyriadau data trwy'ch sianeli dewisol (e-bost, Slack, Telegram). Mewn gwasanaeth archebu gwesty ar-lein Ostrovok.ru Mae pob metrig o'n gwasanaethau yn cael eu ffrydio i InfluxDB ac yn cael eu harddangos yn Grafana, lle mae rhybuddio sylfaenol hefyd wedi'i ffurfweddu. Ar gyfer tasgau fel "angen cyfrifo rhywbeth a'i gymharu â hyn," rydym yn defnyddio Kapacitor.

Triciau ar gyfer prosesu metrigau yn Kapacitor
Mae Kapacitor yn rhan o'r pentwr TICK sy'n gallu prosesu metrigau o InfluxDB. Gall ymuno â dimensiynau lluosog, cyfrifo data defnyddiol o'r data sy'n deillio o hynny, ysgrifennu'r canlyniad yn ôl i InfluxDB, ac anfon rhybuddion i Slack, Telegram, neu e-bost.

Mae gan y pentwr cyfan golwg cŵl a manwl dogfennaeth, ond mae yna bob amser bethau defnyddiol nad ydyn nhw'n cael eu crybwyll yn benodol yn y llawlyfrau. Yn yr erthygl hon, penderfynais gasglu nifer o awgrymiadau defnyddiol, anamlwg o'r fath (disgrifir cystrawen sylfaenol TICKscipt yma) a dangoswch sut y gellir eu cymhwyso gan ddefnyddio'r enghraifft o ddatrys un o'n problemau.

Gadewch i ni fynd!

arnofio a chyfanrif, gwallau cyfrifo

Problem gwbl safonol, wedi'i datrys trwy gastio:

var alert_float = 5.0
var alert_int = 10
data|eval(lambda: float("value") > alert_float OR float("value") < float("alert_int"))

Gan ddefnyddio default()

Os na fydd y tag/maes wedi'i lenwi, bydd gwallau cyfrifo yn digwydd:

|default()
        .tag('status', 'empty')
        .field('value', 0)

llenwi ymuno (mewnol vs. allanol)

Yn ddiofyn, bydd ymuno yn taflu pwyntiau lle nad oes data (mewnol).
Pan fydd fill('null') bydd ymuniad allanol yn cael ei berfformio, ac ar ôl hynny mae angen i chi wneud default() 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 yna rybudd o hyd yma. Os yw un o'r cyfresi (res1 neu res2) yn wag yn yr enghraifft uchod, bydd y gyfres sy'n deillio o hyn (data) hefyd yn wag. Mae sawl problem GitHub ar y pwnc hwn (1633, 1871, 6967) – rydym yn aros am atebion ac yn dioddef ychydig.

Defnyddio amodau mewn cyfrifiadau (os mewn lambda)

|eval(lambda: if("value" > 0, true, false)

Y pum munud olaf o'r biblinell ar gyfer y cyfnod

Er enghraifft, mae angen i chi gymharu gwerthoedd y pum munud diwethaf â'r wythnos flaenorol. Gallwch gymryd dwy set o ddata mewn dau swp ar wahân neu echdynnu rhywfaint o ddata o gyfnod mwy:

 |where(lambda: duration((unixNano(now()) - unixNano("time"))/1000, 1u) < 5m)

Dewis arall ar gyfer y pum munud olaf yw defnyddio nod BarrierNode, sy'n torri data i ffwrdd cyn yr amser penodedig:

|barrier()
        .period(5m)

Enghreifftiau o ddefnyddio templedi Go yn Neges

Mae'r templedi'n cyfateb i'r fformat o'r pecyn testun.templed, isod mae rhai problemau a geir yn aml.

os-arall

Gadewch i ni roi trefn ar bethau a pheidio â sbarduno pobl gyda thestun diangen:

|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 arddangos mwy o wybodaeth yn y neges i ateb y cwestiwn “Pam mae'n sgrechian?”

var warnAlert = 10
  |alert()
    ...
    .message(
       'Today value less then '+string(warnAlert)+'%'
    )

Dynodwr rhybudd unigryw

Mae hon yn nodwedd ddefnyddiol pan fo mwy nag un grŵp yn y data, fel arall dim ond un rhybudd fydd yn cael ei gynhyrchu:

|alert()
      ...
      .id('{{ index .Tags "myname" }}/{{ index .Tags "myfield" }}')

Trinwyr personol

Mae'r rhestr fawr o drinwyr yn cynnwys exec, sy'n eich galluogi i weithredu eich sgript gyda'r paramedrau a basiwyd (stdin) – creadigrwydd pur!

Un o'n sgriptiau personol yw sgript Python bach ar gyfer anfon hysbysiadau i Slack.
Ar y dechrau, roedden ni eisiau anfon delwedd o Grafana mewn neges, wedi'i diogelu gan awdurdodiad. Yna, roedden ni eisiau ysgrifennu "Iawn" yn yr edau ar gyfer y rhybudd blaenorol o'r un grŵp, yn hytrach nag mewn neges ar wahân. Ychydig yn ddiweddarach, roedden ni eisiau ychwanegu'r gwall mwyaf cyffredin o'r X munud diwethaf at y neges.

Pwnc ar wahân yw'r cysylltiad â gwasanaethau eraill ac unrhyw gamau a gychwynnir gan rybudd (dim ond os yw eich monitro'n gweithio'n ddigon da).
Enghraifft o ddisgrifiad trinwr, lle mae slack_handler.py yn ein sgript personol:

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"]

Sut i ddadfygio?

Opsiwn gydag allbwn i logio

|log()
      .level("error")
      .prefix("something")

Gwylio (cli): cynhwysydd -url gwesteiwr-neu-iplogiau :9092 lvl=gwall

Opsiwn gyda httpOut

Yn dangos data yn y biblinell gyfredol:

|httpOut('something')

Gwylio (cael): gwesteiwr-neu-ip:9092/capacitor/v1/tasgau/enw_tasg/rhywbeth

Cynllun gweithredu

  • Mae pob tasg yn dychwelyd coeden weithredu gyda rhifau defnyddiol yn y fformat graffviz.
  • Rydym yn cymryd bloc dot.
  • Gludwch i'r gwyliwr, gadewch i ni fwynhau.

Ble arall allwch chi gael eich cricio?

stamp amser yn influxdb yn ystod ysgrifennu'n ôl

Er enghraifft, rydym yn sefydlu rhybudd ar gyfer swm y ceisiadau yr awr (groupBy(1h)) ac eisiau cofnodi'r rhybudd yn influxdb (i ddangos ffaith y broblem yn braf ar graff yn grafana).

Bydd influxDBOut() yn ysgrifennu'r gwerth amser o'r rhybudd i'r stamp amser, felly bydd y pwynt ar y siart yn cael ei ysgrifennu'n gynharach/hwyrach na chyrhaeddodd y rhybudd.

Pan fo angen cywirdeb: rydym yn osgoi'r broblem hon trwy alw trinwr personol, a fydd yn ysgrifennu data i influxdb gyda'r stamp amser cyfredol.

Docker, adeiladu a defnyddio

Wrth gychwyn, gall kapacitor lwytho tasgau, templedi a thrinwyr o'r cyfeiriadur a bennir yn y ffurfweddiad, yn y bloc [llwytho].

I greu tasg yn gywir, mae angen y pethau canlynol arnoch:

  1. Enw ffeil - yn ehangu i enw id/sgript
  2. Math – ffrwd/swp
  3. dbrp – allweddair ar gyfer nodi pa gronfa ddata + polisi y mae'r sgript yn rhedeg ynddi (dbrp "cyflenwr"."autogen")

Os nad yw unrhyw dasg swp yn cynnwys llinell gyda dbrp, bydd y gwasanaeth cyfan yn gwrthod cychwyn ac yn ysgrifennu amdano'n onest yn y log.

Yn chronograf, i'r gwrthwyneb, ni ddylai'r llinell hon fod yno; ni chaiff ei derbyn trwy'r rhyngwyneb ac mae'n dychwelyd gwall.

Hac adeiladu cynhwysydd: Mae Dockerfile yn cau gyda -1 os oes llinellau gyda //.+dbrp, a fydd yn caniatáu ichi ddeall ar unwaith y rheswm dros fethiant yr adeiladu.

ymuno ag un i lawer

Tasg enghreifftiol: cymerwch y 95fed ganradd o amser gweithredu'r gwasanaeth am wythnos a chymharwch bob munud o'r 10 diwethaf â'r gwerth hwn.

Ni allwch wneud ymuniad un-i-lawer; mae last/mean/median dros grŵp o bwyntiau yn troi'r nod yn nant, a bydd y gwall "ni ellir ychwanegu ymylon anghyfatebol plentyn: batch -> stream" yn cael ei ddychwelyd.

Nid yw canlyniad y swp, fel newidyn yn y mynegiant lambda, yn cael ei amnewid chwaith.

Mae yna opsiwn i gadw'r niferoedd gofynnol o'r swp cyntaf i ffeil trwy udf a llwytho'r ffeil hon trwy sideload.

Beth oedden ni'n ei ddatrys gyda hyn?

Mae gennym tua 100 o ddarparwyr gwestai, a gall pob un ohonynt gael cysylltiadau lluosog, gadewch i ni eu galw'n sianeli. Mae tua 300 o'r sianeli hyn, a gall unrhyw un ohonynt fethu. O'r holl fetrigau a gofnodwyd, byddwn yn monitro'r gyfradd gwallau (ceisiadau a gwallau).

Pam lai Grafana?

Mae gan rybuddion gwall sydd wedi'u ffurfweddu yn Grafana sawl anfantais. Mae rhai yn hollbwysig, tra gellir anwybyddu eraill, yn dibynnu ar y sefyllfa.

Ni all Grafana wneud cyfrifiadau rhyng-ddimensiynol + rhybuddio, ond mae angen y gyfradd (ceisiadau-gwallau)/ceisiadau arnom.

Mae'r gwallau'n edrych yn annymunol:

Triciau ar gyfer prosesu metrigau yn Kapacitor

A llai o ddrwg os edrychwch arno gyda cheisiadau llwyddiannus:

Triciau ar gyfer prosesu metrigau yn Kapacitor

Iawn, gallwn rag-gyfrifo'r gyfradd yn y gwasanaeth cyn Grafana, ac mewn rhai achosion, mae hynny'n iawn. Ond nid yn ein un ni, oherwydd mae gan bob sianel ei chymhareb "normal" ei hun, ac mae rhybuddion yn seiliedig ar werthoedd statig (rydym yn cadw llygad arnyn nhw, gan eu haddasu os ydyn nhw'n rhybuddio'n aml).

Dyma enghreifftiau o "normal" ar gyfer gwahanol sianeli:

Triciau ar gyfer prosesu metrigau yn Kapacitor

Triciau ar gyfer prosesu metrigau yn Kapacitor

Gadewch i ni anwybyddu'r pwynt blaenorol a thybio bod gan bob cyflenwr ddarlun "normal" tebyg. Felly, mae popeth yn iawn nawr, a gallwn ni ymdopi â rhybuddion yn Grafana?
Gallwn ni, ond dydyn ni wir ddim eisiau, oherwydd mae'n rhaid i ni ddewis un o'r opsiynau:
a) gwneud llawer o graffiau ar gyfer pob sianel ar wahân (a'u cynnal yn boenus)
b) gadael un siart gyda'r holl sianeli (a mynd ar goll yn y llinellau lliwgar a'r rhybuddion wedi'u haddasu)

Triciau ar gyfer prosesu metrigau yn Kapacitor

Sut wnaethoch chi hynny?

Unwaith eto, mae enghraifft gychwynnol dda yn y ddogfennaeth (Cyfrifo cyfraddau ar draws cyfresi cysylltiedig), gallwch edrych arno neu ei ddefnyddio fel sail mewn problemau tebyg.

Yr hyn a wnaethom yn y diwedd:

  • ymunwch â dwy bennod mewn ychydig oriau, gan grwpio yn ôl sianeli;
  • rydym yn llenwi'r gyfres yn ôl grwpiau os nad oedd data;
  • rydym yn cymharu canolrif y 10 munud diwethaf â'r data blaenorol;
  • gweiddi os byddwn yn dod o hyd i rywbeth;
  • rydym yn ysgrifennu cyfraddau cyfrifedig a rhybuddion a ddigwyddodd i influxdb;
  • Anfonwch neges ddefnyddiol i Slack.

Yn fy marn i, llwyddon ni i gyflawni popeth roedden ni ei eisiau yn y diwedd mor brydferth â phosibl (a hyd yn oed ychydig yn fwy gyda thrinwyr wedi'u teilwra).

Gallwch edrych ar github.com enghraifft cod и diagram lleiaf (graphviz) sgript wedi'i dderbyn.

Enghraifft o'r cod sy'n deillio o hyn:

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)

Felly beth yw'r casgliad?

Mae Kapacitor yn wych am fonitro a rhybuddio gyda grwpiau lluosog, gan gyflawni cyfrifiadau ychwanegol yn seiliedig ar fetrigau sydd eisoes wedi'u cofnodi, cyflawni gweithredoedd personol, a rhedeg sgriptiau (udf).

Nid yw'r trothwy mynediad yn uchel iawn - rhowch gynnig arni os nad yw Grafana neu offer eraill yn bodloni'ch anghenion yn llawn.

Ffynhonnell: hab.com

Prynu gwesteio dibynadwy ar gyfer gwefannau sydd â diogelwch DDoS, gweinyddwyr VPS VDS 🔥 Prynu cynnal gwefannau dibynadwy gyda diogelwch DDoS, gweinyddion VPS VDS | ProHoster