ምናልባትም ዛሬ ማንም ሰው የአገልግሎት መለኪያዎችን መሰብሰብ ለምን እንደሚያስፈልግ አይጠይቅም. ቀጣዩ አመክንዮአዊ እርምጃ ለተሰበሰቡት መለኪያዎች ማንቂያ ማዘጋጀት ነው, ይህም ለእርስዎ በሚመች ቻናል ውስጥ ስላለው ማንኛውም ልዩነት (ሜል, ስላክ, ቴሌግራም) ያሳውቃል. በኦንላይን የሆቴል ቦታ ማስያዝ አገልግሎት ውስጥ
ካፓሲተር ከInfluxDB መለኪያዎችን ማካሄድ የሚችል የTICK ቁልል አካል ነው። ብዙ መለኪያዎችን በአንድ ላይ ማገናኘት ይችላል (መቀላቀል) ፣ ከተቀበለው መረጃ ጠቃሚ ነገር ያሰላል ፣ ውጤቱን ወደ InfluxDB መልሰው ይፃፉ ፣ ለ Slack/Telegram/mail ማንቂያ ይልካል።
ጠቅላላው ቁልል አሪፍ እና ዝርዝር ነው።
ተንሳፋፊ እና int፣ የስሌት ስህተቶች
ፍጹም ደረጃውን የጠበቀ ችግር፣ በ castes የሚፈታ፡-
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 ላይ በርካታ ቲኬቶች አሉ (
በስሌቶች ውስጥ ሁኔታዎችን መጠቀም (lambda ውስጥ ከሆነ)
|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) ጋር እንዲፈጽሙ ያስችልዎታል - ፈጠራ እና ምንም ተጨማሪ!
ከጉምሩክ ልማዳችን አንዱ ለደካማ ማሳወቂያዎችን ለመላክ ትንሽ የፓይዘን ስክሪፕት ነው።
መጀመሪያ ላይ በመልእክት ውስጥ በፍቃድ የተጠበቀ የግራፋና ሥዕል መላክ እንፈልጋለን። ከዚያ በኋላ፣ ከተመሳሳይ ቡድን ወደ ቀድሞው ማንቂያ በክር ውስጥ እሺን ይፃፉ እንጂ እንደ የተለየ መልእክት አይደለም። ትንሽ ቆይቶ - በመጨረሻዎቹ 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
አማራጭ ከ httpOut ጋር
አሁን ባለው የቧንቧ መስመር ላይ ያለውን መረጃ ያሳያል፡-
|httpOut('something')
ይመልከቱ (አግኝ)
የማስፈጸሚያ ንድፍ
ሌላ ከየት ማግኘት ይችላሉ?
timestamp influxdb በጽሑፍ መልሶ መፃፍ ላይ
ለምሳሌ፣ በሰዓት ለሚቀርቡ ጥያቄዎች ድምር ማንቂያ አዘጋጅተናል (ቡድን በ(1ሰ)) እና በ influxdb ውስጥ የተከሰተውን ማንቂያ መቅዳት እንፈልጋለን (በግራፋና ግራፍ ላይ ያለውን የችግሩን እውነታ በሚያምር ሁኔታ ለማሳየት)።
influxDBOut() የሰዓት እሴቱን ከማንቂያው እስከ የጊዜ ማህተም ይጽፋል፤ በዚህ መሰረት፣ በገበታው ላይ ያለው ነጥብ ማስጠንቀቂያው ከደረሰው ቀደም ብሎ/በኋላ ይፃፋል።
ትክክለኛነት በሚያስፈልግበት ጊዜ፡ በዚህ ችግር ዙሪያ ወደ ብጁ ተቆጣጣሪ በመደወል እንሰራለን፣ ይህም አሁን ካለው የጊዜ ማህተም ጋር መረጃን ወደ ፍሰት ይጽፋል።
docker, መገንባት እና ማሰማራት
በሚነሳበት ጊዜ kapacitor በ [ሎድ] ብሎክ ውስጥ ባለው ውቅረት ውስጥ ከተጠቀሰው ማውጫ ውስጥ ተግባሮችን ፣ አብነቶችን እና ተቆጣጣሪዎችን መጫን ይችላል።
አንድን ተግባር በትክክል ለመፍጠር የሚከተሉትን ነገሮች ያስፈልግዎታል
- የፋይል ስም - ወደ ስክሪፕት መታወቂያ/ስም ተዘርግቷል።
- አይነት - ዥረት / ባች
- dbrp - ስክሪፕቱ በየትኛው የውሂብ ጎታ + ፖሊሲ ውስጥ እንደሚሠራ ለማመልከት ቁልፍ ቃል (dbrp “አቅራቢ” “autogen”)
አንዳንድ የቡድን ተግባር ከ dbrp ጋር መስመር ከሌለው አገልግሎቱ ለመጀመር ፈቃደኛ አይሆንም እና በቅንነት ምዝግብ ማስታወሻ ውስጥ ይጽፋል።
በ chronograf ውስጥ ፣ በተቃራኒው ፣ ይህ መስመር መኖር የለበትም ፣ በይነገጽ ተቀባይነት የለውም እና ስህተት ይፈጥራል።
ኮንቴይነሩን በሚገነቡበት ጊዜ Hack: Dockerfile በ //.+dbrp መስመሮች ካሉ ከ -1 ጋር ይወጣል, ይህም ግንባታውን በሚገጣጠሙበት ጊዜ የውድቀቱን ምክንያት ወዲያውኑ እንዲረዱ ያስችልዎታል.
አንዱን ለብዙዎች መቀላቀል
ምሳሌ ተግባር፡ የአገልግሎቱን የስራ ጊዜ 95ኛ ፐርሰንታይል ለአንድ ሳምንት መውሰድ አለብህ፣ ያለፉት 10 ደቂቃዎች እያንዳንዱን ደቂቃ ከዚህ እሴት ጋር አወዳድር።
ከአንድ እስከ ብዙ መቀላቀል፣ የመጨረሻ/አማካይ/ሚዲያን በቡድን ነጥቦች ላይ ማድረግ አይችሉም፣ መስቀለኛ መንገድን ወደ ዥረት ይቀይረዋል፣ ስህተቱ "የልጆች ያልተዛመዱ ጠርዞችን ማከል አይቻልም፡ ባች -> ዥረት" ይመለሳል።
በላምዳ አገላለጽ ውስጥ እንደ ተለዋዋጭ የቡድን ውጤት እንዲሁ አልተተካም.
አስፈላጊዎቹን ቁጥሮች ከመጀመሪያው ባች ወደ ፋይል በ udf በኩል ለማስቀመጥ እና ይህንን ፋይል በጎን ጭነት ለመጫን አማራጭ አለ.
በዚህ ምን ፈታን?
ወደ 100 የሚጠጉ የሆቴል አቅራቢዎች አሉን ፣ እያንዳንዳቸው ብዙ ግንኙነት ሊኖራቸው ይችላል ፣ ቻናል እንበለው ። ከእነዚህ ውስጥ 300 የሚያህሉ ቻናሎች አሉ፣ እያንዳንዱ ቻናሎች ሊወድቁ ይችላሉ። ከተመዘገቡት መለኪያዎች ሁሉ የስህተት መጠኑን (ጥያቄዎችን እና ስህተቶችን) እንቆጣጠራለን።
ለምን ግራፋና አይሆንም?
በግራፋና ውስጥ የተዋቀሩ የስህተት ማንቂያዎች ብዙ ጉዳቶች አሏቸው። አንዳንዶቹ ወሳኝ ናቸው, አንዳንዶቹ እንደ ሁኔታው ዓይኖችዎን መዝጋት ይችላሉ.
Grafana በመለኪያዎች + ማንቂያዎች መካከል እንዴት እንደሚሰላ አያውቅም ነገር ግን ተመን (ጥያቄዎች-ስህተት)/ጥያቄዎች እንፈልጋለን።
ስህተቶቹ አስቀያሚ ይመስላሉ-
እና ከተሳካላቸው ጥያቄዎች ጋር ሲታይ ያነሰ ክፋት፡-
እሺ፣ ከግራፋና በፊት በአገልግሎቱ ውስጥ ያለውን ዋጋ አስቀድመን ማስላት እንችላለን፣ እና በአንዳንድ ሁኔታዎች ይሄ ይሰራል። ግን በእኛ ውስጥ አይደለም, ምክንያቱም ... ለእያንዳንዱ ቻናል የራሱ ሬሾ እንደ “መደበኛ” ይቆጠራል ፣ እና ማንቂያዎች በስታቲስቲክስ እሴቶች መሠረት ይሰራሉ (በአይኖቻችን እንፈልጋቸዋለን ፣ ተደጋጋሚ ማንቂያዎች ካሉ እንለውጣቸዋለን)።
እነዚህ ለተለያዩ ቻናሎች የ"መደበኛ" ምሳሌዎች ናቸው፡
የቀደመውን ነጥብ ችላ ብለን "የተለመደው" ምስል ለሁሉም አቅራቢዎች ተመሳሳይ ነው ብለን እንገምታለን. አሁን ሁሉም ነገር ደህና ነው፣ እና በግራፋና ውስጥ ባሉ ማንቂያዎች ማግኘት እንችላለን?
እንችላለን፣ ግን በእርግጥ አንፈልግም፣ ምክንያቱም ከአማራጮች ውስጥ አንዱን መምረጥ አለብን፡-
ሀ) ለእያንዳንዱ ቻናል ብዙ ግራፎችን ለየብቻ ይስሩ (እና በሚያሳምም ያጅቧቸው)
ለ) ከሁሉም ቻናሎች ጋር አንድ ገበታ ይተው (እና በቀለማት ያሸበረቁ መስመሮች እና ብጁ ማንቂያዎች ውስጥ ይጠፉ)
እንዴት አደረጋችሁት?
እንደገና፣ በሰነዱ ውስጥ ጥሩ መነሻ ምሳሌ አለ (
በመጨረሻ ያደረግነው፡-
- በጥቂት ሰዓታት ውስጥ ሁለት ተከታታዮችን መቀላቀል, በሰርጦች መቧደን;
- ምንም ውሂብ ከሌለ ተከታታዩን በቡድን ይሙሉ;
- ያለፉትን 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) በማስኬድ ረገድ ጥሩ ነው።
የመግባት እንቅፋት በጣም ከፍተኛ አይደለም - ግራፋና ወይም ሌሎች መሳሪያዎች ፍላጎቶችዎን ሙሉ በሙሉ ካላሟሉ ይሞክሩት።
ምንጭ: hab.com