Trik pikeun ngolah métrik dina Kapacitor

Paling dipikaresep, kiwari taya sahijieun nanya naha perlu pikeun ngumpulkeun metrics jasa. Léngkah logis salajengna nyaéta nyetél waspada pikeun métrik anu dikumpulkeun, anu bakal ngabéjaan ngeunaan panyimpangan data dina saluran anu cocog pikeun anjeun (mail, Slack, Telegram). Dina layanan booking hotél online Ostrovok.ru sadaya métrik tina jasa kami dituang kana InfluxDB sareng ditampilkeun dina Grafana, sareng peringatan dasar ogé dikonpigurasi di dinya. Pikeun tugas kawas "anjeun kudu ngitung hal tur dibandingkeun jeung eta," kami nganggo Kapacitor.

Trik pikeun ngolah métrik dina Kapacitor
Kapacitor mangrupikeun bagian tina tumpukan TICK anu tiasa ngolah métrik tina InfluxDB. Éta tiasa nyambungkeun sababaraha pangukuran babarengan (gabung), ngitung hal anu mangpaat tina data anu ditampi, nyerat hasilna deui ka InfluxDB, ngirim waspada ka Slack / Telegram / mail.

Sakabéh tumpukan téh tiis tur lengkep dokuméntasi, tapi bakal salawasna aya hal mangpaat anu teu eksplisit dituduhkeun dina manual. Dina tulisan ieu, kuring mutuskeun pikeun ngumpulkeun sababaraha tip anu mangpaat, henteu jelas (sintaks dasar TICKscipt dijelaskeun. di dieu) jeung nunjukkeun kumaha éta bisa dilarapkeun ngagunakeun conto ngarengsekeun salah sahiji masalah urang.

Hayu urang balik!

ngambang & int, kasalahan itungan

Masalah standar pisan, direngsekeun ngaliwatan kasta:

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

Ngagunakeun standar()

Lamun tag/widang teu dieusian, kasalahan itungan bakal lumangsung:

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

eusian gabung (batin vs luar)

Sacara standar, gabung bakal miceun titik dimana teu aya data (batin).
Kalawan eusian ( 'null'), hiji gabung luar bakal dipigawé, nu satutasna anjeun kedah ngalakukeun standar a () sarta eusian nilai kosong:

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

Masih aya nuansa di dieu. Dina conto di luhur, lamun salah sahiji runtuyan (res1 atanapi res2) kosong, runtuyan hasilna (data) ogé bakal kosong. Aya sababaraha tiket dina topik ieu dina Github (1633, 1871, 6967) - kami ngantosan perbaikan sareng sangsara sakedik.

Ngagunakeun kaayaan dina itungan (upami dina lambda)

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

Lima menit panungtungan ti pipa pikeun periode

Salaku conto, anjeun kedah ngabandingkeun nilai lima menit terakhir sareng minggu sateuacana. Anjeun tiasa nyandak dua bets data dina dua bets misah atanapi nimba bagian tina data tina periode nu leuwih gede:

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

Alternatif pikeun lima menit terakhir nyaéta ngagunakeun BarrierNode, anu motong data sateuacan waktos anu ditangtukeun:

|barrier()
        .period(5m)

Conto ngagunakeun témplat Go dina pesen

Témplat pakait sareng format tina bungkusan téks.templateDi handap ieu aya sababaraha puzzles remen encountered.

upami-sanés

Urang nempatkeun hal-hal dina urutan sareng henteu memicu jalma ku téks sakali deui:

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

Dua digit sanggeus titik decimal dina pesen

Ningkatkeun kabacaan pesen:

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

Ngalegaan variabel dina pesen

Kami ningalikeun langkung seueur inpormasi dina pesen pikeun ngajawab patarosan "Naha ngagorowok"?

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

Identifier ngageter unik

Ieu mangrupikeun hal anu diperyogikeun nalika aya langkung ti hiji grup dina data, upami henteu ngan ukur hiji waspada anu bakal dibangkitkeun:

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

Custom pawang urang

Daptar badag pawang ngawengku exec, nu ngidinan Anjeun pikeun ngaéksekusi Aksara anjeun kalawan parameter diliwatan (stdin) - kreativitas sarta nanaon deui!

Salah sahiji adat istiadat urang nyaéta skrip Python leutik pikeun ngirim béwara pikeun slack.
Mimitina, urang hoyong ngirim gambar grafana anu ditangtayungan otorisasi dina pesen. Saatos éta, nyerat OK dina thread ka ngageter saméméhna ti grup sarua, sarta lain salaku pesen misah. Sakedap deui - tambahkeun kana pesen kasalahan anu paling umum dina menit X terakhir.

Topik anu misah nyaéta komunikasi sareng jasa anu sanés sareng tindakan naon waé anu diprakarsai ku waspada (ngan upami ngawaskeun anjeun tiasa dianggo cekap).
Conto déskripsi pawang, dimana slack_handler.py mangrupikeun skrip anu ditulis sorangan:

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

Kumaha debug?

Pilihan kalayan kaluaran log

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

Lalajo (cli): kapacitor -url host-atawa-ip: 9092 log lvl = kasalahan

Pilihan sareng httpOut

Némbongkeun data dina pipa ayeuna:

|httpOut('something')

Lalajo (meunang): host-atawa-ip:9092/kapacitor/v1/tasks/task_name/hal

Skéma palaksanaan

  • Unggal tugas mulih hiji tangkal palaksanaan kalawan angka mangpaat dina format nu grafviz.
  • Candak blok dot.
  • Tempelkeun kana panempo, ngarasakeun.

Dimana deui anjeun tiasa kéngingkeun rake?

timestamp di influxdb on writeback

Contona, urang nyetel hiji ngageter pikeun jumlah requests per jam (groupBy (1h)) jeung hayang ngarekam ngageter nu lumangsung dina influxdb (pikeun beautifully némbongkeun kanyataan masalah dina grafik dina grafana).

influxDBOut () bakal nyerat nilai waktos ti ngageter ka timestamp; sasuai, titik dina bagan bakal ditulis saméméhna / engké ti waspada anjog.

Nalika akurasi diperlukeun: urang ngungkulan masalah ieu ku nelepon hiji Handler custom, nu bakal nulis data ka influxdb jeung timestamp ayeuna.

docker, ngawangun sarta deployment

Dina ngamimitian, kapacitor tiasa ngamuat tugas, témplat sareng pawang tina diréktori anu ditetepkeun dina konfigurasi dina blok [beban].

Pikeun nyiptakeun tugas anu leres, anjeun peryogi hal-hal ieu:

  1. Ngaran koropak - dimekarkeun jadi skrip id / ngaran
  2. Jenis - stream / bets
  3. dbrp - kecap konci pikeun nunjukkeun pangkalan data + kawijakan mana anu dijalankeun ku naskah (dbrp "supplier." "autogen")

Upami sababaraha tugas angkatan henteu ngandung garis sareng dbrp, sadaya jasa bakal nampik ngamimitian sareng jujur ​​​​saurna nyerat ngeunaan éta dina log.

Dina chronograf, sabalikna, garis ieu teu kudu aya; eta teu ditarima ngaliwatan panganteur jeung dibangkitkeun kasalahan.

Hack nalika ngawangun wadahna: Dockerfile kaluar kalawan -1 lamun aya garis kalawan //.+dbrp, nu bakal ngidinan Anjeun pikeun langsung ngartos alesan gagalna nalika assembling wangunan.

gabung hiji mun loba

Conto tugas: anjeun kedah nyandak persentil ka-95 tina waktos operasi jasa salami saminggu, bandingkeun unggal menit 10 terakhir sareng nilai ieu.

Anjeun teu bisa ngalakukeun hiji-ka-loba gabung, panungtungan / mean / median leuwih sakelompok titik robah titik kana stream a, kasalahan "teu bisa nambahkeun edges mismatched anak: bets -> stream" bakal balik.

Hasil tina bets, salaku variabel dina ekspresi lambda, ogé henteu diganti.

Aya hiji pilihan pikeun ngahemat angka nu diperlukeun ti bets kahiji ka file via udf tur muka file ieu via sideload.

Naon anu urang ngajawab kalawan ieu?

Kami gaduh sakitar 100 panyadia hotél, masing-masing tiasa gaduh sababaraha sambungan, hayu urang nyebat saluran. Aya kira-kira 300 saluran ieu, unggal saluran tiasa murag. Tina sadaya métrik anu dirékam, urang bakal ngawas tingkat kasalahan (paménta sareng kasalahan).

Naha henteu grafana?

Tanda kasalahan anu dikonpigurasi dina Grafana ngagaduhan sababaraha kalemahan. Sababaraha anu kritis, sababaraha anjeun tiasa nutup panon anjeun, gumantung kana kaayaan.

Grafana teu nyaho kumaha carana ngitung antara pangukuran + alerting, tapi urang kudu laju (requests-kasalahan) / requests.

Kasalahan katingalina parah:

Trik pikeun ngolah métrik dina Kapacitor

Sareng kirang jahat upami ditingali kalayan pamundut anu suksés:

Trik pikeun ngolah métrik dina Kapacitor

Oke, urang tiasa tos ngitung ongkos dina layanan saméméh grafana, sarta dina sababaraha kasus ieu bakal jalan. Tapi henteu di urang, sabab ... Pikeun unggal saluran, rasio sorangan dianggap "normal", sareng panggeuing tiasa dianggo dumasar kana nilai statik (urang milarian aranjeunna ku panon urang, robih upami aya panggeuing sering).

Ieu conto "normal" pikeun saluran anu béda:

Trik pikeun ngolah métrik dina Kapacitor

Trik pikeun ngolah métrik dina Kapacitor

Urang malire titik saméméhna tur nganggap yén gambar "normal" téh sarupa pikeun sakabéh suppliers. Ayeuna sadayana henteu kunanaon, sareng urang tiasa kéngingkeun béwara dina grafana?
Urang tiasa, tapi urang leres-leres henteu hoyong, sabab urang kedah milih salah sahiji pilihan:
a) ngadamel seueur grafik pikeun tiap saluran nyalira (sareng nyerina ngiringanana)
b) tinggalkeun hiji bagan sareng sadaya saluran (sareng leungit dina garis warni sareng panggeuing khusus)

Trik pikeun ngolah métrik dina Kapacitor

Kumaha anjeun ngalakukeun eta?

Sakali deui, aya conto awal anu saé dina dokuméntasi (Ngitung ongkos dina séri gabungan), bisa diintip atawa dijadikeun dadasar dina masalah nu sarupa.

Naon anu urang laksanakeun dina tungtungna:

  • gabung dua séri dina sababaraha jam, dikelompokkeun dumasar saluran;
  • eusian runtuyan dumasar grup lamun euweuh data;
  • ngabandingkeun median tina 10 menit panungtungan kalawan data saméméhna;
  • urang ngagorowok lamun urang manggihan hiji hal;
  • urang nulis ongkos diitung sarta ngabejaan anu lumangsung dina influxdb;
  • ngirim pesen mangpaat pikeun slack.

Dina pamanggih kuring, urang junun ngahontal sagalana urang hayang meunang dina tungtungna (komo saeutik deui kalawan pawang custom) sakumaha beautifully jéntré.

Anjeun tiasa ningali github.com conto kode и sirkuit minimal (graphviz) naskah anu dihasilkeun.

Conto kode anu dihasilkeun:

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)

Naon kacindekan?

Kapacitor hébat dina ngalakukeun ngawas-ngawas kalawan kebat groupings, ngajalankeun itungan tambahan dumasar kana métrik geus dirékam, ngalakukeun lampah custom tur ngajalankeun Aksara (udf).

Halangan pikeun asupna henteu luhur pisan - cobian upami grafana atanapi alat sanés henteu nyugemakeun kahayang anjeun.

sumber: www.habr.com

Tambahkeun komentar