కెపాసిటర్‌లో కొలమానాలను ప్రాసెస్ చేయడానికి ఉపాయాలు

చాలా మటుకు, ఈ రోజు సేవా కొలమానాలను ఎందుకు సేకరించాల్సిన అవసరం ఉందని ఎవరూ అడగరు. సేకరించిన కొలమానాల కోసం హెచ్చరికను సెటప్ చేయడం తదుపరి తార్కిక దశ, ఇది మీకు అనుకూలమైన ఛానెల్‌లలో (మెయిల్, స్లాక్, టెలిగ్రామ్) డేటాలో ఏవైనా వ్యత్యాసాల గురించి తెలియజేస్తుంది. ఆన్‌లైన్ హోటల్ బుకింగ్ సేవలో Ostrovok.ru మా సేవల యొక్క అన్ని కొలమానాలు ఇన్‌ఫ్లక్స్‌డిబిలో పోస్తారు మరియు గ్రాఫానాలో ప్రదర్శించబడతాయి మరియు ప్రాథమిక హెచ్చరికలు కూడా అక్కడ కాన్ఫిగర్ చేయబడతాయి. "మీరు దేనినైనా లెక్కించాలి మరియు దానితో సరిపోల్చాలి" వంటి పనుల కోసం మేము కెపాసిటర్‌ని ఉపయోగిస్తాము.

కెపాసిటర్‌లో కొలమానాలను ప్రాసెస్ చేయడానికి ఉపాయాలు
Kapacitor అనేది InfluxDB నుండి కొలమానాలను ప్రాసెస్ చేయగల TICK స్టాక్‌లో భాగం. ఇది అనేక కొలతలను ఒకదానితో ఒకటి కనెక్ట్ చేయగలదు (చేరవచ్చు), అందుకున్న డేటా నుండి ఉపయోగకరమైనదాన్ని లెక్కించవచ్చు, ఫలితాన్ని ఇన్‌ఫ్లక్స్‌డిబికి తిరిగి వ్రాయవచ్చు, స్లాక్/టెలిగ్రామ్/మెయిల్‌కి హెచ్చరికను పంపవచ్చు.

మొత్తం స్టాక్ బాగుంది మరియు వివరంగా ఉంది డాక్యుమెంటేషన్, కానీ మాన్యువల్స్‌లో స్పష్టంగా సూచించబడని ఉపయోగకరమైన విషయాలు ఎల్లప్పుడూ ఉంటాయి. ఈ ఆర్టికల్‌లో, నేను అలాంటి అనేక ఉపయోగకరమైన, అస్పష్టమైన చిట్కాలను సేకరించాలని నిర్ణయించుకున్నాను (TICKscipt యొక్క ప్రాథమిక వాక్యనిర్మాణం వివరించబడింది ఇక్కడ) మరియు మా సమస్యల్లో ఒకదాన్ని పరిష్కరించే ఉదాహరణను ఉపయోగించి వాటిని ఎలా అన్వయించవచ్చో చూపండి.

లెట్ యొక్క వెళ్ళి!

ఫ్లోట్ & ఇంట్, గణన లోపాలు

కులాల ద్వారా పరిష్కరించబడిన ఒక సంపూర్ణ ప్రామాణిక సమస్య:

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)

చేరడానికి పూరించండి (లోపలి vs బాహ్య)

డిఫాల్ట్‌గా, చేరడం డేటా లేని పాయింట్‌లను విస్మరిస్తుంది (లోపలి).
ఫిల్ ('శూన్య')తో, ఒక బాహ్య జాయిన్ చేయబడుతుంది, దాని తర్వాత మీరు డిఫాల్ట్()ని చేసి, ఖాళీ విలువలను పూరించాలి:

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)

చివరి ఐదు నిమిషాలకు ప్రత్యామ్నాయంగా బారియర్‌నోడ్‌ని ఉపయోగించడం, ఇది పేర్కొన్న సమయానికి ముందే డేటాను ఆపివేస్తుంది:

|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) అమలు చేయడానికి మిమ్మల్ని అనుమతిస్తుంది - సృజనాత్మకత మరియు మరేమీ లేదు!

మా ఆచారాలలో ఒకటి స్లాక్‌కి నోటిఫికేషన్‌లను పంపడానికి ఒక చిన్న పైథాన్ స్క్రిప్ట్.
మొదట, మేము మెసేజ్‌లో అధికార-రక్షిత గ్రాఫానా చిత్రాన్ని పంపాలనుకున్నాము. ఆ తర్వాత, థ్రెడ్‌లో సరే అని వ్రాయండి, అదే సమూహం నుండి మునుపటి హెచ్చరికకు ప్రత్యేక సందేశంగా కాదు. కొద్దిసేపటి తర్వాత - చివరి 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): కెపాసిటర్ -url హోస్ట్-లేదా-ip:9092 లాగ్‌లు lvl=ఎర్రర్

httpOut తో ఎంపిక

ప్రస్తుత పైప్‌లైన్‌లో డేటాను చూపుతుంది:

|httpOut('something')

చూడండి (పొందండి): హోస్ట్-లేదా-ip:9092/kapacitor/v1/tasks/task_name/something

అమలు రేఖాచిత్రం

  • ప్రతి పని ఫార్మాట్‌లో ఉపయోగకరమైన సంఖ్యలతో అమలు ట్రీని అందిస్తుంది గ్రాఫ్విజ్.
  • ఒక బ్లాక్ తీసుకోండి చుక్క.
  • వీక్షకుడికి అతికించండి, ఆనందించండి.

మీరు రేక్ ఎక్కడ పొందవచ్చు?

రైట్‌బ్యాక్‌పై ఇన్‌ఫ్లక్స్‌డిబిలో టైమ్‌స్టాంప్

ఉదాహరణకు, మేము గంటకు అభ్యర్థనల మొత్తానికి (groupBy(1h)) హెచ్చరికను సెటప్ చేస్తాము మరియు influxdbలో సంభవించిన హెచ్చరికను రికార్డ్ చేయాలనుకుంటున్నాము (గ్రాఫానాలోని గ్రాఫ్‌లో సమస్య యొక్క వాస్తవాన్ని అందంగా చూపించడానికి).

influxDBOut() హెచ్చరిక నుండి టైమ్‌స్టాంప్‌కు సమయ విలువను వ్రాస్తుంది; తదనుగుణంగా, చార్ట్‌లోని పాయింట్ హెచ్చరిక వచ్చిన దానికంటే ముందుగా/తర్వాత వ్రాయబడుతుంది.

ఖచ్చితత్వం అవసరమైనప్పుడు: కస్టమ్ హ్యాండ్లర్‌కు కాల్ చేయడం ద్వారా మేము ఈ సమస్యను పరిష్కరిస్తాము, ఇది ప్రస్తుత టైమ్‌స్టాంప్‌తో డేటాను influxdbకి వ్రాస్తుంది.

డాకర్, బిల్డ్ మరియు విస్తరణ

ప్రారంభంలో, కెపాసిటర్ [లోడ్] బ్లాక్‌లోని కాన్ఫిగరేషన్‌లో పేర్కొన్న డైరెక్టరీ నుండి టాస్క్‌లు, టెంప్లేట్‌లు మరియు హ్యాండ్లర్‌లను లోడ్ చేయగలదు.

పనిని సరిగ్గా సృష్టించడానికి, మీకు ఈ క్రింది అంశాలు అవసరం:

  1. ఫైల్ పేరు - స్క్రిప్ట్ ఐడి/పేరుగా విస్తరించబడింది
  2. రకం - స్ట్రీమ్/బ్యాచ్
  3. dbrp – స్క్రిప్ట్ ఏ డేటాబేస్ + విధానంలో నడుస్తుందో సూచించడానికి కీవర్డ్ (dbrp “సప్లయర్.” “ఆటోజెన్”)

కొన్ని బ్యాచ్ టాస్క్‌లో dbrpతో లైన్ లేకపోతే, మొత్తం సేవ ప్రారంభించడానికి నిరాకరిస్తుంది మరియు లాగ్‌లో దాని గురించి నిజాయితీగా వ్రాస్తుంది.

క్రోనోగ్రాఫ్‌లో, దీనికి విరుద్ధంగా, ఈ లైన్ ఉండకూడదు; ఇది ఇంటర్‌ఫేస్ ద్వారా అంగీకరించబడదు మరియు లోపాన్ని సృష్టిస్తుంది.

కంటైనర్‌ను నిర్మించేటప్పుడు హ్యాక్ చేయండి: //.+dbrpతో లైన్‌లు ఉంటే డాకర్‌ఫైల్ -1తో నిష్క్రమిస్తుంది, ఇది బిల్డ్‌ను అసెంబ్లింగ్ చేసేటప్పుడు వైఫల్యానికి కారణాన్ని వెంటనే అర్థం చేసుకోవడానికి మిమ్మల్ని అనుమతిస్తుంది.

ఒకరితో అనేకం చేరండి

ఉదాహరణ పని: మీరు ఒక వారం పాటు సేవ యొక్క ఆపరేటింగ్ సమయంలో 95వ శాతాన్ని తీసుకోవాలి, ఈ విలువతో చివరి 10 నిమిషాన్ని సరిపోల్చండి.

మీరు ఒకటి నుండి చాలా వరకు చేరలేరు, పాయింట్ల సమూహంలో చివరి/సగటు/మధ్యస్థం నోడ్‌ను స్ట్రీమ్‌గా మారుస్తుంది, “పిల్లల సరిపోలని అంచులను జోడించలేరు: బ్యాచ్ -> స్ట్రీమ్” అనే లోపం తిరిగి వస్తుంది.

లాంబ్డా వ్యక్తీకరణలో వేరియబుల్‌గా బ్యాచ్ యొక్క ఫలితం కూడా ప్రత్యామ్నాయం కాదు.

మొదటి బ్యాచ్ నుండి అవసరమైన నంబర్‌లను udf ద్వారా ఫైల్‌కి సేవ్ చేయడానికి మరియు సైడ్‌లోడ్ ద్వారా ఈ ఫైల్‌ను లోడ్ చేయడానికి ఒక ఎంపిక ఉంది.

దీనితో మనం ఏమి పరిష్కరించాము?

మాకు దాదాపు 100 మంది హోటల్ సరఫరాదారులు ఉన్నారు, వారిలో ప్రతి ఒక్కరికి అనేక కనెక్షన్‌లు ఉండవచ్చు, దానిని ఛానెల్ అని పిలుద్దాం. వీటిలో దాదాపు 300 ఛానెల్‌లు ఉన్నాయి, ఒక్కో ఛానెల్ పడిపోవచ్చు. రికార్డ్ చేయబడిన అన్ని కొలమానాలలో, మేము లోపం రేటును (అభ్యర్థనలు మరియు లోపాలు) పర్యవేక్షిస్తాము.

గ్రాఫానా ఎందుకు కాదు?

గ్రాఫానాలో కాన్ఫిగర్ చేయబడిన ఎర్రర్ అలర్ట్‌లు అనేక ప్రతికూలతలను కలిగి ఉన్నాయి. కొన్ని క్లిష్టమైనవి, కొన్ని పరిస్థితిని బట్టి మీరు కళ్ళు మూసుకోవచ్చు.

కొలతలు + హెచ్చరికల మధ్య ఎలా లెక్కించాలో గ్రాఫానాకు తెలియదు, కానీ మనకు రేటు (అభ్యర్థనలు-లోపాలు)/అభ్యర్థనలు అవసరం.

లోపాలు అసహ్యంగా కనిపిస్తాయి:

కెపాసిటర్‌లో కొలమానాలను ప్రాసెస్ చేయడానికి ఉపాయాలు

విజయవంతమైన అభ్యర్థనలతో వీక్షించినప్పుడు తక్కువ చెడు:

కెపాసిటర్‌లో కొలమానాలను ప్రాసెస్ చేయడానికి ఉపాయాలు

సరే, మేము గ్రాఫానాకు ముందు సేవలో రేట్‌ను ముందే లెక్కించవచ్చు మరియు కొన్ని సందర్భాల్లో ఇది పని చేస్తుంది. కానీ మనలో కాదు, ఎందుకంటే... ప్రతి ఛానెల్‌కు దాని స్వంత నిష్పత్తి “సాధారణం”గా పరిగణించబడుతుంది మరియు హెచ్చరికలు స్టాటిక్ విలువల ప్రకారం పనిచేస్తాయి (మేము వాటిని మా కళ్ళతో చూస్తాము, తరచుగా హెచ్చరికలు ఉంటే వాటిని మార్చండి).

ఇవి వేర్వేరు ఛానెల్‌ల కోసం "సాధారణ" ఉదాహరణలు:

కెపాసిటర్‌లో కొలమానాలను ప్రాసెస్ చేయడానికి ఉపాయాలు

కెపాసిటర్‌లో కొలమానాలను ప్రాసెస్ చేయడానికి ఉపాయాలు

మేము మునుపటి పాయింట్‌ను విస్మరిస్తాము మరియు "సాధారణ" చిత్రం అన్ని సరఫరాదారులకు సమానంగా ఉంటుందని ఊహిస్తాము. ఇప్పుడు అంతా బాగానే ఉంది మరియు గ్రాఫానాలో అలర్ట్‌లతో మనం పొందగలమా?
మేము చేయగలము, కానీ మేము నిజంగా కోరుకోవడం లేదు, ఎందుకంటే మేము ఎంపికలలో ఒకదాన్ని ఎంచుకోవాలి:
ఎ) ప్రతి ఛానెల్‌కు వేర్వేరుగా చాలా గ్రాఫ్‌లను తయారు చేయండి (మరియు బాధాకరంగా వాటితో పాటు)
బి) అన్ని ఛానెల్‌లతో ఒక చార్ట్‌ను వదిలివేయండి (మరియు రంగురంగుల పంక్తులు మరియు అనుకూలీకరించిన హెచ్చరికలను కోల్పోవడం)

కెపాసిటర్‌లో కొలమానాలను ప్రాసెస్ చేయడానికి ఉపాయాలు

దాన్ని ఎలా చేసావు?

మళ్ళీ, డాక్యుమెంటేషన్‌లో మంచి ప్రారంభ ఉదాహరణ ఉంది (చేరిన శ్రేణిలో రేట్లను గణిస్తోంది), ఇలాంటి సమస్యలలో పీక్ చేయవచ్చు లేదా ప్రాతిపదికగా తీసుకోవచ్చు.

మేము చివరికి ఏమి చేసాము:

  • కొన్ని గంటల్లో రెండు సిరీస్‌లలో చేరండి, ఛానెల్‌ల వారీగా సమూహం చేయడం;
  • డేటా లేనట్లయితే సమూహం ద్వారా సిరీస్‌ను పూరించండి;
  • మునుపటి డేటాతో చివరి 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

ఒక వ్యాఖ్యను జోడించండి