Ҳилаҳо барои коркарди метрика дар Kapacitor

Эҳтимол, имрӯз касе намепурсад, ки чаро ҷамъоварии метрикаи хидматрасонӣ зарур аст. Қадами навбатии мантиқӣ ин насб кардани огоҳӣ барои ченакҳои ҷамъовардашуда мебошад, ки дар бораи ҳама гуна инҳироф дар маълумот дар каналҳои барои шумо мувофиқ (почта, Slack, Telegram) огоҳ мекунад. Дар хидмати бронкунии меҳмонхонаҳо Ostrovok.ru ҳама нишондиҳандаҳои хидматҳои мо ба InfluxDB рехта мешаванд ва дар Grafana намоиш дода мешаванд ва огоҳии асосӣ низ дар он ҷо танзим карда мешавад. Барои вазифаҳое мисли "шумо бояд чизеро ҳисоб кунед ва бо он муқоиса кунед", мо Kapacitor -ро истифода мебарем.

Ҳилаҳо барои коркарди метрика дар Kapacitor
Kapacitor як қисми стеки TICK мебошад, ки метавонад ченакҳоро аз InfluxDB коркард кунад. Он метавонад якчанд андозагириҳоро бо ҳам пайваст кунад (ҳамроҳ кунад), аз маълумоти гирифташуда чизи муфидро ҳисоб кунад, натиҷаро ба InfluxDB нависед, ба Slack/Telegram/mail ҳушдор фиристад.

Тамоми анбор сард ва муфассал аст ҳуҷҷатҳо, аммо ҳамеша чизҳои муфид хоҳанд буд, ки дар дастурҳо ба таври возеҳ нишон дода нашудаанд. Дар ин мақола, ман қарор додам, ки як қатор чунин маслиҳатҳои муфид ва ғайриоддӣ ҷамъоварӣ кунам (синтаксиси асосии TICKscipt тавсиф карда шудааст) дар ин ҷо) ва нишон диҳед, ки чӣ гуна онҳоро бо мисоли ҳалли яке аз мушкилоти мо истифода бурдан мумкин аст.

Биёед биравем!

float & int, хатогиҳои ҳисоб

Масъалаи комилан стандартӣ, ки тавассути кастаҳо ҳал карда мешавад:

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

Истифодаи пешфарз()

Агар тег/майдон пур карда нашавад, хатогиҳои ҳисобкунӣ ба амал меоянд:

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

пур кардани ҳамроҳ (дарунӣ ва берунӣ)

Бо нобаёнӣ, ҳамроҳ нуқтаҳоеро, ки маълумот мавҷуд нест (дохилӣ) нест мекунад.
Ҳангоми пур кардан('null') пайвасти беруна иҷро мешавад, ки пас аз он шумо бояд пешфарзро () иҷро кунед ва арзишҳои холиро пур кунед:

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

Дар ин ҷо ҳанӯз як нозуки вуҷуд дорад. Дар мисоли дар боло овардашуда, агар яке аз силсила (res1 ё res2) холӣ бошад, силсилаи (маълумот) дар натиҷа низ холӣ хоҳад буд. Дар Github якчанд чиптаҳо оид ба ин мавзӯъ мавҷуданд (1633, 1871, 6967) — мунтазири ислох шуда, андаке азоб мекашем.

Истифодаи шартҳо дар ҳисобҳо (агар дар ламбда бошад)

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

Панҷ дақиқаи охир аз қубур барои давра

Масалан, шумо бояд арзишҳои панҷ дақиқаи охирро бо ҳафтаи қаблӣ муқоиса кунед. Шумо метавонед ду маҷмӯи маълумотро дар ду гурӯҳи алоҳида гиред ё як қисми маълумотро аз давраи калонтар гиред:

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

Алтернатива барои панҷ дақиқаи охир ин истифодаи BarrierNode аст, ки маълумотро пеш аз вақти муайяншуда қатъ мекунад:

|barrier()
        .period(5m)

Намунаҳои истифодаи қолибҳои Go дар паём

Шаблонҳо ба формати баста мувофиқат мекунанд матн.шаблонДар зер баъзе муаммоҳои зуд-зуд дучор мешаванд.

агар-дигар

Мо чизҳоро ба тартиб меорем ва одамонро бори дигар бо матн таҳрик намедиҳем:

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

Ду рақам пас аз нуқтаи даҳӣ дар паём

Беҳтар кардани хониши паём:

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

Васеъ кардани тағирёбандаҳо дар паём

Мо маълумоти бештарро дар паём нишон медиҳем, то ба саволи "Чаро фарёд мезанад"?

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

Муайянкунандаи нодири огоҳӣ

Ин як чизи зарурӣ аст, вақте ки дар маълумот зиёда аз як гурӯҳ мавҷуд аст, вагарна танҳо як огоҳӣ тавлид мешавад:

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

Коркарди фармоишӣ

Рӯйхати калони коркардкунандагон дорои exec мебошад, ки ба шумо имкон медиҳад скрипти худро бо параметрҳои додашуда (stdin) иҷро кунед - эҷодкорӣ ва чизи дигар!

Яке аз расмҳои мо скрипти хурди Python барои фиристодани огоҳиномаҳо ба сустшавӣ мебошад.
Дар аввал, мо мехостем, ки дар паём як тасвири графанаи бо иҷозати муҳофизатшуда фиристем. Баъдан, дар ришта ба огоҳии қаблии ҳамон гурӯҳ Хуб нависед, на ҳамчун паёми алоҳида. Каме дертар - ба паём хатои маъмултаринро дар X дақиқаи охир илова кунед.

Мавзӯи ҷудогона иртибот бо хидматҳои дигар ва ҳама гуна амалҳое мебошад, ки тавассути огоҳӣ оғоз мешаванд (танҳо агар мониторинги шумо ба қадри кофӣ хуб кор кунад).
Намунаи тавсифи коркардкунанда, ки дар он slack_handler.py скрипти худнависи мост:

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

Чӣ тавр ислоҳ кардан?

Опсия бо баромади гузориш

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

Watch (cli): kapacitor -url host-or-ip:9092 гузоришҳо lvl=хато

Опсия бо httpOut

Маълумотро дар лӯлаи ҷорӣ нишон медиҳад:

|httpOut('something')

тамошо кунед (гиред): host-or-ip:9092/kapacitor/v1/tasks/task_name/чизе

Диаграммаи иҷро

  • Ҳар як вазифа дарахти иҷроро бо рақамҳои муфид дар формат бармегардонад графвиз.
  • Блок гиред нуқта.
  • Онро ба тамошобин часбонед, лаззат баред.

Боз аз куҷо шумо рейка пайдо карда метавонед?

тамғаи вақт дар influxdb дар навиштан

Масалан, мо барои маблағи дархостҳо дар як соат (groupBy(1h)) огоҳӣ таъсис медиҳем ва мехоҳем ҳушдореро, ки дар influxdb рух додааст, сабт кунем (барои зебо нишон додани далели мушкилот дар график дар графана).

influxDBOut() арзиши вақтро аз ҳушдор то тамғаи вақт менависад; мувофиқан, нуқтаи диаграмма пештар/дертар аз огоҳии расида навишта мешавад.

Вақте ки дақиқ талаб карда мешавад: мо ин мушкилотро тавассути занг задан ба коркарди фармоишӣ ҳал мекунем, ки маълумотро ба influxdb бо тамғаи вақти ҷорӣ менависад.

докер, сохтан ва ҷойгиркунӣ

Ҳангоми оғозёбӣ, конденсатор метавонад вазифаҳо, қолибҳо ва коркардкунандагонро аз директорияи дар конфигуратсия дар блоки [боркунӣ] муайяншуда бор кунад.

Барои дуруст сохтани вазифа ба шумо чизҳои зерин лозиманд:

  1. Номи файл - ба скрипт id/name васеъ карда шудааст
  2. Навъи - ҷараён / партия
  3. dbrp - калимаи калидӣ барои нишон додани он, ки скрипт дар кадом пойгоҳи додаҳо кор мекунад + сиёсати (dbrp "таъминкунанда." "автоген")

Агар ягон супориши партия сатри dbrp надошта бошад, тамоми хадамот оғоз карданро рад мекунад ва дар ин бора ростқавлона дар гузориш менависад.

Дар хронограф, баръакс, ин хат набояд вуҷуд дошта бошад, он тавассути интерфейс қабул карда намешавад ва хатогӣ ба вуҷуд меорад.

Ҳангоми сохтани контейнер ҳак кардан: Dockerfile бо -1 мебарояд, агар сатрҳо бо //.+dbrp мавҷуд бошанд, ки ин ба шумо имкон медиҳад, ки сабаби нокомиро ҳангоми васл кардани сохтмон фавран фаҳмед.

ба бисёриҳо ҳамроҳ шавед

Мисол супориш: шумо бояд 95 фоизи вақти кори хидматро дар тӯли як ҳафта гиред, ҳар як дақиқаи 10-и охиринро бо ин арзиш муқоиса кунед.

Шумо наметавонед пайвасти як ба бисёр анҷом диҳед, охирин/миёна/медиан дар болои гурӯҳи нуқтаҳо гиреҳро ба ҷараён табдил медиҳад, хатои "илова кардани кунҷҳои номувофиқи кӯдак: партия -> ҷараён" баргардонида мешавад.

Натиҷаи гурӯҳ ҳамчун тағирёбанда дар ифодаи ламбда низ иваз карда намешавад.

Имконият мавҷуд аст, ки рақамҳои заруриро аз бастаи аввал ба файл тавассути udf захира кунед ва ин файлро тавассути боркунӣ бор кунед.

Мо бо ин чиро ҳал кардем?

Мо тақрибан 100 таъминкунандагони меҳмонхона дорем, ки ҳар яки онҳо метавонанд якчанд робита дошта бошанд, биёед онро канал бигӯем. Тақрибан 300-тои ин каналҳо вуҷуд доранд, ки ҳар яке аз каналҳо метавонанд афтад. Аз ҳамаи нишондиҳандаҳои сабтшуда, мо сатҳи хатогиҳоро (дархостҳо ва хатоҳо) назорат хоҳем кард.

Чаро графана нест?

Огоҳиҳои хатогӣ, ки дар Grafana танзим карда шудаанд, як қатор камбудиҳо доранд. Баъзеҳо интиқодӣ доранд, баъзеҳо, вобаста ба вазъият, шумо метавонед чашмони худро пӯшед.

Grafana намедонад, ки чӣ тавр ҳисоб кардани байни андозагирӣ + огоҳӣ, аммо ба мо меъёри (дархостҳо-хатоҳо)/дархостҳо лозим аст.

Хатогиҳо бад ба назар мерасанд:

Ҳилаҳо барои коркарди метрика дар Kapacitor

Ва бадӣ камтар ҳангоми дидани дархостҳои муваффақ:

Ҳилаҳо барои коркарди метрика дар Kapacitor

Хуб, мо метавонем нархро дар хидмат пеш аз графана пешакӣ ҳисоб кунем ва дар баъзе ҳолатҳо ин кор хоҳад кард. Аммо дар мо не, зеро... барои ҳар як канал таносуби худи он "муқаррарӣ" ҳисобида мешавад ва огоҳиҳо мувофиқи арзишҳои статикӣ кор мекунанд (мо онҳоро бо чашмони худ меҷӯем, агар ҳушдорҳои зуд-зуд пайдо шаванд, онҳоро тағир медиҳем).

Инҳо намунаҳои "муқаррарӣ" барои каналҳои гуногун мебошанд:

Ҳилаҳо барои коркарди метрика дар Kapacitor

Ҳилаҳо барои коркарди метрика дар Kapacitor

Мо нуқтаи пешинаро нодида мегирем ва фарз мекунем, ки тасвири "муқаррарӣ" барои ҳама таъминкунандагон якхела аст. Ҳоло ҳама чиз хуб аст ва мо метавонем бо огоҳиҳо дар графана кор кунем?
Мо метавонем, аммо мо воқеан намехоҳем, зеро мо бояд яке аз вариантҳоро интихоб кунем:
а) барои ҳар як канал алоҳида графикҳои зиёде созед (ва онҳоро бо дард ҳамроҳӣ кунед)
б) як диаграммаро бо ҳама каналҳо тарк кунед (ва дар хатҳои рангоранг ва огоҳиҳои фармоишӣ гум шавед)

Ҳилаҳо барои коркарди метрика дар Kapacitor

Шумо инро чӣ тавр кардед?

Боз, дар ҳуҷҷатҳо намунаи хуби ибтидоӣ мавҷуд аст (Ҳисоб кардани нархҳо дар силсилаи ҳамроҳшуда), мумкин аст ба назар гирифта шавад ё дар мушкилоти шабеҳ ҳамчун асос гирифта шавад.

Дар охир чӣ кор кардем:

  • дар тӯли чанд соат ба ду силсила ҳамроҳ шавед, аз рӯи каналҳо гурӯҳбандӣ кунед;
  • силсиларо аз рӯи гурӯҳ пур кунед, агар маълумот мавҷуд набошад;
  • муқоисаи медиани 10 дақиқаи охир бо маълумоти қаблӣ;
  • агар чизе пайдо кунем фарёд мезанем;
  • мо нархҳо ва огоҳиҳои ҳисобшударо, ки дар influxdb рух додаанд, менависем;
  • паёми муфид ба суст фиристед.

Ба андешаи ман, мо тавонистем ҳама чизеро, ки дар охир ба даст овардан мехостем (ва ҳатто каме бештар бо коркардкунандагони фармоишӣ) ба қадри имкон зебо ба даст орем.

Шумо метавонед ба github.com нигаред мисоли код и схемаи минималӣ (graphviz) скрипти натиҷа.

Намунаи рамзи натиҷа:

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)

Хулоса чист?

Kapacitor дар иҷрои огоҳиҳои мониторинг бо як қатор гурӯҳҳо, анҷом додани ҳисобҳои иловагӣ дар асоси ченакҳои аллакай сабтшуда, иҷрои амалҳои фармоишӣ ва иҷро кардани скриптҳо (udf) аъло аст.

Монеаи воридшавӣ чандон баланд нест - кӯшиш кунед, ки агар графана ё дигар асбобҳо хоҳишҳои шуморо пурра қонеъ накунанд.

Манбаъ: will.com

Илова Эзоҳ