په Kapacitor کې د میټریک پروسس کولو چلونه

ډیری احتمال، نن ورځ هیڅوک پوښتنه نه کوي چې ولې د خدماتو میترونو راټولول اړین دي. بل منطقي ګام د راټول شوي میټریکونو لپاره د خبرتیا تنظیم کول دي ، کوم چې به ستاسو لپاره مناسب چینلونو کې ډیټا کې د هرډول انحراف په اړه خبر کړي (میل ، سلیک ، ټیلیګرام). د آنلاین هوټل بکینګ خدمت کې Ostrovok.ru زموږ د خدماتو ټول میټریکونه په InfluxDB کې اچول شوي او په ګرافانا کې ښودل شوي، او اساسي خبرتیا هم هلته ترتیب شوې ده. د کارونو لپاره لکه "تاسو اړتیا لرئ یو څه محاسبه کړئ او د هغې سره پرتله کړئ ،" موږ کاپیسیټر کاروو.

په Kapacitor کې د میټریک پروسس کولو چلونه
Kapacitor د TICK سټیک برخه ده چې کولی شي د InfluxDB څخه میټریک پروسس کړي. دا کولی شي ډیری پیمانه یوځای سره وصل کړي (یوځای شي)، د ترلاسه شوي معلوماتو څخه یو څه ګټور محاسبه کړي، پایله بیرته InfluxDB ته ولیکئ، سلیک / ټیلیګرام / میل ته خبرتیا واستوئ.

ټوله سټیک یخ او مفصل دی اسناد، مګر دلته به تل ګټور شیان وي چې په لارښود کې په څرګنده توګه ندي ښودل شوي. پدې مقاله کې ، ما پریکړه وکړه چې یو شمیر داسې ګټورې ، غیر څرګند لارښوونې راټولې کړم (د 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)

شمولیت ډک کړئ (داخلي او بهر)

د ډیفالټ په توګه، یوځای کیدل به هغه ټکي رد کړي چیرې چې هیڅ معلومات شتون نلري (داخلي).
د ډکولو سره ('نول')، یو بهرنی یوځای کیدل به ترسره شي، وروسته له دې چې تاسو اړتیا لرئ یو ډیفالټ () وکړئ او خالي ارزښتونه ډک کړئ:

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

دلته لا تر اوسه یو نزاکت شتون لري. په پورتنۍ بېلګه کې، که یوه لړۍ (res1 یا res2) خالي وي، پایله لرونکې لړۍ (ډاټا) به هم خالي وي. په ګیتوب کې پدې موضوع کې ډیری ټکټونه شتون لري (1633, 1871, 6967) – موږ د اصلاح او یو څه رنځ په تمه یو.

په محاسبه کې د شرایطو کارول (که په لیمبډا کې)

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

د مودې لپاره د پایپ لاین څخه وروستي پنځه دقیقې

د مثال په توګه، تاسو اړتیا لرئ چې د تیرو پنځو دقیقو ارزښتونه د تیرې اونۍ سره پرتله کړئ. تاسو کولی شئ د معلوماتو دوه بستې په دوه جلا بستونو کې واخلئ یا د لویې مودې څخه د ډیټا یوه برخه استخراج کړئ:

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

د تیرو پنځو دقیقو لپاره بدیل به د BarrierNode کارول وي، کوم چې د ټاکل شوي وخت څخه مخکې ډاټا قطع کوي:

|barrier()
        .period(5m)

په پیغام کې د ګو ټیمپلیټ کارولو مثالونه

ټیمپلیټونه د کڅوړې فارمیټ سره مطابقت لري text.templateلاندې ځینې پزلونه دي چې ډیری وختونه ورسره مخ کیږي.

که-نور

موږ شیان ترتیب کوو او یو ځل بیا د متن سره خلک نه هڅوو:

|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 سکریپټ دی.
په لومړي سر کې، موږ غوښتل چې په یو پیغام کې د اجازه لیک څخه خوندي ګرافانا عکس واستوو. وروسته، د ورته ګروپ څخه مخکیني خبرتیا ته په تار کې OK ولیکئ، نه د جلا پیغام په توګه. یو څه وروسته - پیغام ته اضافه کړئ په تیرو 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")

کتل (cli): kapacitor -url کوربه-یا-ip:9092 logs lvl = تېروتنه

د httpOut سره اختیار

په اوسني پایپ لاین کې ډاټا ښیې:

|httpOut('something')

وګورئ (ترلاسه کړئ): کوربه-یا-ip:9092/kapacitor/v1/tasks/task_name/something

د اجرا کولو سکیم

  • هره دنده په بڼه کې د ګټورو شمیرو سره د اعدام ونې بیرته راګرځوي ګراف ویز.
  • یو بلاک واخلئ DoT.
  • په لیدونکي کې یې پیسټ کړئ، خوند واخلئ.

تاسو بل چیرته ریک ترلاسه کولی شئ؟

د رایټ بیک په انفلکس ډی بی کې مهال ویش

د مثال په توګه، موږ په هر ساعت کې د غوښتنو د مجموعې لپاره خبرتیا جوړه کړه (groupBy(1h)) او غواړو هغه خبرتیا ثبت کړو چې په influxdb کې پیښ شوي (د ګرافانا په ګراف کې د ستونزې حقیقت په ښکلي ډول څرګندولو لپاره).

influxDBOut() به د وخت ارزښت د خبرتیا څخه ټایم سټمپ ته ولیکي؛ په دې اساس، په چارټ کې ټکی به د خبرتیا له رسیدو دمخه / وروسته لیکل کیږي.

کله چې دقت ته اړتیا وي: موږ د ګمرک هینډلر په زنګ وهلو سره د دې ستونزې په شاوخوا کې کار کوو، کوم چې به د اوسني مهال ویش سره influxdb ته ډاټا ولیکي.

ډاکر، جوړول او ځای پرځای کول

په پیل کې، کپیسیټر کولی شي د [لوډ] بلاک کې په ترتیب کې مشخص شوي لارښود څخه دندې، ټیمپلیټونه او سمبالونکي بار کړي.

د یوې دندې په سمه توګه رامینځته کولو لپاره، تاسو لاندې شیانو ته اړتیا لرئ:

  1. د فایل نوم - په سکریپټ ID/نوم کې پراخ شوی
  2. ډول - جریان/بیچ
  3. dbrp - کلیدي کلمه چې دا په ګوته کړي چې کوم ډیټابیس + پالیسي سکریپټ په کې چلیږي (dbrp "سپارونکی." "آټوجن")

که چیرې د بیچ ځینې دندې د dbrp سره کرښه ونه لري، ټول خدمت به د پیل کولو څخه انکار وکړي او په صادقانه توګه به په لاګ کې د هغې په اړه ولیکئ.

په کرونوګراف کې، برعکس، دا کرښه باید شتون ونلري؛ دا د انٹرفیس له لارې نه منل کیږي او یوه تېروتنه رامنځته کوي.

د کانټینر جوړولو په وخت کې هیک کړئ: Dockerfile د -1 سره وځي که چیرې د //.+dbrp سره کرښې شتون ولري، کوم چې تاسو ته اجازه درکوي چې د جوړیدو په وخت کې د ناکامۍ په علت سمدلاسه پوه شئ.

یو له ډیرو سره یوځای شئ

د مثال دنده: تاسو اړتیا لرئ د یوې اونۍ لپاره د خدماتو عملیاتي وخت 95 فیصده واخلئ ، د دې ارزښت سره د وروستي 10 دقیقې هره دقیقه پرتله کړئ.

تاسو نشئ کولی له یو څخه تر ډیری پورې یوځای شئ، د پوائنټونو په یوې ډلې کې وروستی/مینین/میډین نوډ په جریان کې بدلوي، تېروتنه "د ماشوم سره مطابقت لرونکي څنډې نه شي اضافه کولی: بیچ -> جریان" به بیرته راشي.

د یوې بستې پایله، د لامبډا بیان کې د متغیر په توګه، هم بدیل نه دی.

دلته یو اختیار شتون لري چې اړین شمیرې له لومړۍ بستې څخه فایل ته د udf له لارې خوندي کړئ او دا فایل د سایډلوډ له لارې پورته کړئ.

موږ له دې سره څه حل کړل؟

موږ شاوخوا 100 هوټل عرضه کوونکي لرو، هر یو کولی شي څو اړیکې ولري، راځئ چې دا یو چینل ووایو. د دې چینلونو څخه نږدې 300 شتون لري، هر یو چینل کولی شي سقوط وکړي. د ټولو ثبت شویو میترونو څخه، موږ به د خطا کچه وڅیړو (غوښتنې او غلطی).

ولې ګرافنا نه؟

په ګرافانا کې ترتیب شوي د خطا خبرتیاوې ډیری زیانونه لري. ځینې ​​یې مهم دي، ځینې تاسو کولی شئ خپلې سترګې وتړئ، د وضعیت پورې اړه لري.

ګرافانا نه پوهیږي چې څنګه د اندازه کولو + خبرتیا ترمینځ محاسبه وکړي ، مګر موږ نرخ ته اړتیا لرو (غوښتنې - تېروتنې)/غوښتنې.

تېروتنې ناوړه ښکاري:

په Kapacitor کې د میټریک پروسس کولو چلونه

او لږ بد کله چې د بریالي غوښتنو سره لیدل کیږي:

په Kapacitor کې د میټریک پروسس کولو چلونه

ښه، موږ کولی شو د ګرافانا دمخه په خدمت کې نرخ محاسبه کړو، او په ځینو مواردو کې دا به کار وکړي. مګر زموږ کې نه، ځکه ... د هر چینل لپاره خپل تناسب "نورمال" ګڼل کیږي، او خبرتیاوې د جامد ارزښتونو سره سم کار کوي (موږ دوی د خپلو سترګو سره ګورو، که په مکرر ډول خبرتیاوې شتون ولري دوی بدل کړئ).

دا د مختلف چینلونو لپاره د "عادي" مثالونه دي:

په Kapacitor کې د میټریک پروسس کولو چلونه

په Kapacitor کې د میټریک پروسس کولو چلونه

موږ پخوانی ټکی له پامه غورځوو او فرض کوو چې "نورمال" انځور د ټولو عرضه کونکو لپاره ورته دی. اوس هرڅه سم دي ، او موږ کولی شو په ګرافانا کې د خبرتیاو سره ترلاسه کړو؟
موږ کولی شو، مګر موږ واقعیا نه غواړو، ځکه چې موږ باید یو له انتخابونو څخه غوره کړو:
الف) د هر چینل لپاره په جلا توګه ډیری ګرافونه جوړ کړئ (او په درد سره ورسره یوځای شئ)
ب) د ټولو چینلونو سره یو چارټ پریږدئ (او په رنګین لینونو او دودیز شوي خبرتیاو کې ورک شئ)

په Kapacitor کې د میټریک پروسس کولو چلونه

څنګه یې وکړل؟

یوځل بیا ، په اسنادو کې یو ښه پیل شوی مثال شتون لري (د یوځای شوي لړۍ په اوږدو کې د نرخونو محاسبه)، په ورته ستونزو کې د اساس په توګه لیدل کیدی شي یا اخیستل کیدی شي.

په پای کې مو څه وکړل:

  • په څو ساعتونو کې دوه لړۍ سره یوځای شئ، د چینلونو لخوا ګروپ کول؛
  • د ګروپ په واسطه لړۍ ډک کړئ که چیرې معلومات شتون نلري؛
  • د تیرو 10 دقیقو منځنۍ اندازه د تیرو معلوماتو سره پرتله کړئ؛
  • موږ چیغې کوو که موږ یو څه ومومو؛
  • موږ محاسبه شوي نرخونه او خبرتیاوې لیکو چې په influxdb کې پیښ شوي؛
  • سست ته یو ګټور پیغام واستوئ.

زما په نظر، موږ هر هغه څه ترلاسه کړل چې موږ یې غوښتل په پای کې ترلاسه کړو (او حتی د ګمرک هینډلرانو سره یو څه نور) څومره چې ممکنه وي.

تاسو کولی شئ په github.com کې وګورئ د کوډ مثال и لږترلږه سرکټ (ګرافیز) پایله لرونکی سکریپټ.

د پایلې کوډ یوه بیلګه:

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)

پایله څه ده؟

کپیسیټر د ډیری ګروپونو سره د څارنې خبرتیاو ترسره کولو کې عالي دی ، د دمخه ثبت شوي میټریکونو پراساس اضافي محاسبې ترسره کول ، دودیز کړنې ترسره کول او سکریپټونه چلول (udf).

د ننوتلو خنډ ډیر لوړ ندی - هڅه وکړئ که چیرې ګرافانا یا نور وسایل ستاسو غوښتنې پوره نه کړي.

سرچینه: www.habr.com

Add a comment