Ke trik nouvèl pou trete metrik nan Kapacitor

Gen plis chans, jodi a pèsonn pa mande poukisa li nesesè kolekte mezi sèvis yo. Pwochen etap ki lojik la se mete yon alèt pou mezi yo kolekte, ki pral fè konnen nenpòt devyasyon nan done yo nan chanèl ki bon pou ou (lapòs, Slack, Telegram). Nan sèvis la anrjistreman otèl sou entènèt Ostrovok.ru tout paramèt sèvis nou yo vide nan InfluxDB epi yo parèt nan Grafana, epi alèt debaz yo tou configuré la. Pou travay tankou "ou bezwen kalkile yon bagay epi konpare ak li," nou itilize Kapacitor.

Ke trik nouvèl pou trete metrik nan Kapacitor
Kapacitor se yon pati nan pil TICK la ki ka trete mezi ki soti nan InfluxDB. Li ka konekte plizyè mezi ansanm (join), kalkile yon bagay itil nan done yo resevwa, ekri rezilta a tounen nan InfluxDB, voye yon alèt nan Slack / Telegram / lapòs.

Pile a tout antye se fre ak detaye dokimantasyon, men ap toujou gen bagay itil ki pa endike klèman nan manyèl yo. Nan atik sa a, mwen te deside kolekte yon kantite konsèy itil, ki pa evidan (sentaks debaz TICKscipt yo dekri. isit la) epi montre kijan yo ka aplike lè l sèvi avèk yon egzanp pou rezoud youn nan pwoblèm nou yo.

Ale!

float & int, erè kalkil

Yon pwoblèm absoliman estanda, rezoud atravè kas:

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

Sèvi ak default ()

Si yon tag/champ pa ranpli, erè kalkil ap fèt:

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

ranpli rantre (entèn vs ekstèn)

Pa default, rantre nan pral jete pwen kote pa gen okenn done (enteryè).
Avèk fill('null'), yo pral fè yon rantre deyò, apre sa ou bezwen fè yon default () epi ranpli valè vid yo:

var data = res1
    |join(res2)
        .as('res1', 'res2)
        .fill('null')
    |default()
        .field('res1.value', 0.0)
        .field('res2.value', 100.0)

Genyen toujou yon nuans isit la. Nan egzanp ki anwo a, si youn nan seri yo (res1 oswa res2) vid, seri a ki kapab lakòz (done) ap tou vid. Gen plizyè tikè sou sijè sa a sou Github (1633, 1871, 6967) – nap tann ranje ak soufrans yon ti kras.

Sèvi ak kondisyon nan kalkil (si nan lambda)

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

Dènye senk minit soti nan tiyo a pou peryòd la

Pou egzanp, ou bezwen konpare valè senk dènye minit yo ak semèn anvan an. Ou ka pran de lo done nan de lo separe oswa ekstrè yon pati nan done yo nan yon peryòd ki pi gwo:

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

Yon altènatif pou senk dènye minit yo ta dwe sèvi ak yon BarrierNode, ki koupe done anvan lè espesifye a:

|barrier()
        .period(5m)

Egzanp yo sèvi ak modèl Go nan mesaj

Modèl yo koresponn ak fòma ki soti nan pake a tèks.modèlAnba la a se kèk devinèt souvan rankontre.

si-lòt bagay

Nou mete bagay yo nan lòd epi yo pa deklanche moun ki gen tèks yon lòt fwa ankò:

|alert()
    ...
    .message(
        '{{ if eq .Level "OK" }}It is ok now{{ else }}Chief, everything is broken{{end}}'
    )

De chif apre pwen desimal nan mesaj la

Amelyore lizibilite nan mesaj la:

|alert()
    ...
    .message(
        'now value is {{ index .Fields "value" | printf "%0.2f" }}'
    )

Agrandi varyab nan mesaj

Nou montre plis enfòmasyon nan mesaj la pou reponn kesyon "Poukisa li rele"?

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

Idantifyan alèt inik

Sa a se yon bagay ki nesesè lè gen plis pase yon gwoup nan done yo, otreman yon sèl alèt pral pwodwi:

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

Manadjè koutim

Gwo lis moun kap okipe yo gen ladan exec, ki pèmèt ou egzekite script ou a ak paramèt yo pase (stdin) - kreyativite e pa gen anyen plis!

Youn nan koutim nou yo se yon ti script Python pou voye notifikasyon nan slack.
Okòmansman, nou te vle voye yon foto grafana otorizasyon pwoteje nan yon mesaj. Apre sa, ekri OK nan fil la nan alèt anvan an soti nan menm gwoup la, epi yo pa kòm yon mesaj separe. Yon ti kras pita - ajoute nan mesaj la erè ki pi komen nan dènye X minit yo.

Yon sijè separe se kominikasyon ak lòt sèvis ak nenpòt aksyon inisye pa yon alèt (sèlman si siveyans ou a travay ase byen).
Yon egzanp yon deskripsyon moun k ap okipe, kote slack_handler.py se script nou ekri pwòp tèt ou:

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

Ki jan yo debogaj?

Opsyon ak pwodiksyon boutèy demi lit

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

Gade (cli): kapacitor -url lame-oswa-ip:9092 mòso bwa lvl = erè

Opsyon ak httpOut

Montre done nan tiyo aktyèl la:

|httpOut('something')

Gade (jwenn): lame-oswa-ip:9092/kapacitor/v1/tasks/task_name/yon bagay

Dyagram ekzekisyon

  • Chak travay retounen yon pye bwa ekzekisyon ak nimewo itil nan fòma a graphviz.
  • Pran yon blòk dot.
  • Kole li nan visualiseur, jwi.

Ki lòt kote ou ka jwenn yon rato?

timestamp nan influxdb sou writeback

Pou egzanp, nou mete yon alèt pou sòm demann pou chak èdtan (groupBy(1h)) epi nou vle anrejistre alèt ki te fèt nan influxdb (pou montre trè byen reyalite pwoblèm nan sou graf la nan grafana).

influxDBOut() pral ekri valè tan ki soti nan alèt la ak timestamp kòmsadwa, pwen an sou tablo a pral ekri pi bonè/pi ta pase alèt la te rive.

Lè yo mande presizyon: nou travay sou pwoblèm sa a lè nou rele yon moun kap okipe, ki pral ekri done sou influxdb ak timestamp aktyèl la.

docker, bati ak deplwaman

Nan demaraj, kapacitor ka chaje travay, modèl ak moun kap okipe yo nan anyè ki espesifye nan konfigirasyon an nan blòk [chaj la].

Pou kreye yon travay kòrèkteman, ou bezwen bagay sa yo:

  1. Non dosye - elaji nan id/non script
  2. Kalite - kouran / pakèt
  3. dbrp - mo kle pou endike ki baz done + politik script la ap kouri (dbrp "founisè." "autogen")

Si kèk travay pakèt pa genyen yon liy ak dbrp, tout sèvis la pral refize kòmanse epi yo pral onètman ekri sou li nan boutèy la.

Nan chronograf, okontrè, liy sa a pa ta dwe egziste li pa aksepte nan koòdone a ak jenere yon erè.

Hack lè bati yon veso: Dockerfile sòti ak -1 si gen liy ak //.+dbrp, ki pral pèmèt ou imedyatman konprann rezon ki fè echèk la lè rasanble bati a.

rantre youn nan anpil

Egzanp travay: ou bezwen pran 95yèm percentile nan tan fonksyone sèvis la pou yon semèn, konpare chak minit nan 10 dènye yo ak valè sa a.

Ou pa ka fè yon sèl-a-anpil rantre, dènye / vle di / medyàn sou yon gwoup pwen vire ne a nan yon kouran, erè a "pa ka ajoute kwen timoun ki pa matche: pakèt -> kouran" ap retounen.

Rezilta yon pakèt, kòm yon varyab nan yon ekspresyon lambda, pa ranplase tou.

Gen yon opsyon pou konsève pou nimewo ki nesesè yo soti nan premye pakèt la nan yon dosye atravè udf epi chaje fichye sa a atravè sideload.

Kisa nou te rezoud ak sa?

Nou gen anviwon 100 founisè otèl, chak nan yo ka gen plizyè koneksyon, ann rele li yon chanèl. Gen apeprè 300 nan chanèl sa yo, chak nan chanèl yo ka tonbe. Nan tout mezi yo anrejistre, nou pral kontwole pousantaj erè a (demann ak erè).

Poukisa pa grafana?

Alèt erè configuré nan Grafana gen plizyè dezavantaj. Gen kèk ki kritik, kèk ou ka fèmen je ou a, tou depann de sitiyasyon an.

Grafana pa konnen ki jan yo kalkile ant mezi + alèt, men nou bezwen yon pousantaj (demann-erè) / demann.

Erè yo sanble dezagreyab:

Ke trik nouvèl pou trete metrik nan Kapacitor

Ak mwens sa ki mal lè yo wè ak demann siksè:

Ke trik nouvèl pou trete metrik nan Kapacitor

Oke, nou ka pre-kalkile pousantaj la nan sèvis la anvan grafana, ak nan kèk ka sa a pral travay. Men, pa nan nou, paske... pou chak chanèl rapò pwòp li yo konsidere kòm "nòmal", ak alèt travay dapre valè estatik (nou gade ak je nou, chanje si gen alèt souvan).

Sa yo se egzanp "nòmal" pou diferan chanèl:

Ke trik nouvèl pou trete metrik nan Kapacitor

Ke trik nouvèl pou trete metrik nan Kapacitor

Nou inyore pwen anvan an epi sipoze ke foto "nòmal" la sanble pou tout founisè yo. Koulye a, tout bagay anfòm, epi nou ka jwenn ak alèt nan grafana?
Nou kapab, men nou reyèlman pa vle, paske nou dwe chwazi youn nan opsyon yo:
a) fè yon anpil nan graf pou chak chanèl separeman (epi fè mal akonpaye yo)
b) kite yon tablo ak tout chanèl (epi pèdi nan liy kolore yo ak alèt Customized)

Ke trik nouvèl pou trete metrik nan Kapacitor

Ki jan ou te fè li?

Ankò, gen yon bon egzanp kòmanse nan dokiman an (Kalkile pousantaj atravè seri ansanm), yo ka gade oswa pran kòm yon baz nan pwoblèm ki sanble.

Ki sa nou te fè nan fen:

  • rantre nan de seri nan kèk èdtan, gwoupman pa chanèl;
  • ranpli seri a pa gwoup si pa te gen okenn done;
  • konpare medyàn 10 dènye minit yo ak done anvan yo;
  • nou rele si nou jwenn yon bagay;
  • nou ekri pousantaj yo kalkile ak alèt ki te fèt nan influxdb;
  • voye yon mesaj itil bay slack.

Nan opinyon mwen, nou jere reyalize tout sa nou te vle jwenn nan fen a (e menm yon ti kras plis ak moun kap okipe) kòm bèl ke posib.

Ou ka gade nan github.com egzanp kòd и sikwi minim (graphviz) script ki kapab lakòz.

Yon egzanp kòd ki kapab lakòz:

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)

Ki konklizyon an?

Kapacitor se gwo nan fè siveyans-alèt ak yon pakèt moun sou gwoupman, fè kalkil adisyonèl ki baze sou mezi deja anrejistre, fè aksyon koutim ak kouri scripts (udf).

Baryè a pou antre pa trè wo - eseye li si grafana oswa lòt zouti pa konplètman satisfè dezi ou yo.

Sous: www.habr.com

Achte hosting serye pou sit ki gen pwoteksyon DDoS, sèvè VPS VDS 🔥 Achte yon hébergement sit entènèt serye ak pwoteksyon DDoS, sèvè VPS VDS | ProHoster