自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

Prometheus告警規(guī)則管理

存儲(chǔ) 存儲(chǔ)軟件
Prometheus支持用戶(hù)自定義Rule規(guī)則。Rule分為兩類(lèi),一類(lèi)是Recording Rule,另一類(lèi)是Alerting Rule。Recording Rule的主要目的是通過(guò)PromQL可以實(shí)時(shí)對(duì)Prometheus中采集到的樣本數(shù)據(jù)進(jìn)行查詢(xún),聚合以及其它各種運(yùn)算操作。

[[419847]]

什么是Rule

Prometheus支持用戶(hù)自定義Rule規(guī)則。Rule分為兩類(lèi),一類(lèi)是Recording Rule,另一類(lèi)是Alerting Rule。Recording Rule的主要目的是通過(guò)PromQL可以實(shí)時(shí)對(duì)Prometheus中采集到的樣本數(shù)據(jù)進(jìn)行查詢(xún),聚合以及其它各種運(yùn)算操作。而在某些PromQL較為復(fù)雜且計(jì)算量較大時(shí),直接使用PromQL可能會(huì)導(dǎo)致Prometheus響應(yīng)超時(shí)的情況。這時(shí)需要一種能夠類(lèi)似于后臺(tái)批處理的機(jī)制能夠在后臺(tái)完成這些復(fù)雜運(yùn)算的計(jì)算,對(duì)于使用者而言只需要查詢(xún)這些運(yùn)算結(jié)果即可。Prometheus通過(guò)Recoding Rule規(guī)則支持這種后臺(tái)計(jì)算的方式,可以實(shí)現(xiàn)對(duì)復(fù)雜查詢(xún)的性能優(yōu)化,提高查詢(xún)效率。

今天主要帶來(lái)告警規(guī)則的分析。Prometheus中的告警規(guī)則允許你基于PromQL表達(dá)式定義告警觸發(fā)條件,Prometheus后端對(duì)這些觸發(fā)規(guī)則進(jìn)行周期性計(jì)算,當(dāng)滿(mǎn)足觸發(fā)條件后則會(huì)觸發(fā)告警通知。

什么是告警Rule

告警是prometheus的一個(gè)重要功能,接下來(lái)從源碼的角度來(lái)分析下告警的執(zhí)行流程。

怎么定義告警Rule

一條典型的告警規(guī)則如下所示:

  1. groups: 
  2. name: example 
  3.   rules: 
  4.   - alert: HighErrorRate 
  5.     #指標(biāo)需要在觸發(fā)告警之前的10分鐘內(nèi)大于0.5。 
  6.     expr: job:request_latency_seconds:mean5m{job="myjob"} > 0.5 
  7.     for: 10m 
  8.     labels: 
  9.       severity: page 
  10.     annotations: 
  11.       summary: High request latency 
  12.       description: description info 

在告警規(guī)則文件中,我們可以將一組相關(guān)的規(guī)則設(shè)置定義在一個(gè)group下。在每一個(gè)group中我們可以定義多個(gè)告警規(guī)則(rule)。一條告警規(guī)則主要由以下幾部分組成:

  • alert:告警規(guī)則的名稱(chēng)。
  • expr:基于PromQL表達(dá)式告警觸發(fā)條件,用于計(jì)算是否有時(shí)間序列滿(mǎn)足該條件。
  • for:評(píng)估等待時(shí)間,可選參數(shù)。用于表示只有當(dāng)觸發(fā)條件持續(xù)一段時(shí)間后才發(fā)送告警。在等待期間新產(chǎn)生告警的狀態(tài)為pending。
  • labels:自定義標(biāo)簽,允許用戶(hù)指定要附加到告警上的一組附加標(biāo)簽。
  • annotations:用于指定一組附加信息,比如用于描述告警詳細(xì)信息的文字等,annotations的內(nèi)容在告警產(chǎn)生時(shí)會(huì)一同作為參數(shù)發(fā)送到Alertmanager。

Rule管理器

規(guī)則管理器會(huì)根據(jù)配置的規(guī)則,基于規(guī)則PromQL表達(dá)式告警的觸發(fā)條件,用于計(jì)算是否有時(shí)間序列滿(mǎn)足該條件。在滿(mǎn)足該條件時(shí),將告警信息發(fā)送給告警服務(wù)。

  1. type Manager struct { 
  2.  opts     *ManagerOptions //外部的依賴(lài) 
  3.  groups   map[string]*Group //當(dāng)前的規(guī)則組 
  4.  mtx      sync.RWMutex //規(guī)則管理器讀寫(xiě)鎖 
  5.  block    chan struct{}  
  6.  done     chan struct{}  
  7.  restored bool  
  8.  
  9.  logger log.Logger  
  • opts(*ManagerOptions類(lèi)型):記錄了Manager實(shí)例使用到的其他模塊,例如storage模塊、notify模塊等。
  • groups(map[string]*Group類(lèi)型):記錄了所有的rules.Group實(shí)例,其中key由rules.Group的名稱(chēng)及其所在的配置文件構(gòu)成。
  • mtx(sync.RWMutex類(lèi)型):在讀寫(xiě)groups字段時(shí)都需要獲取該鎖進(jìn)行同步。

讀取Rule組配置

在Prometheus Server啟動(dòng)的過(guò)程中,首先會(huì)調(diào)用Manager.Update()方法加載Rule配置文件并進(jìn)行解析,其大致流程如下。

  • 調(diào)用Manager.LoadGroups()方法加載并解析Rule配置文件,最終得到rules.Group實(shí)例集合。
  • 停止原有的rules.Group實(shí)例,啟動(dòng)新的rules.Group實(shí)例。其中會(huì)為每個(gè)rules.Group實(shí)例啟動(dòng)一個(gè)goroutine,它會(huì)關(guān)聯(lián)rules.Group實(shí)例下的全部PromQL查詢(xún)。
  1. func (m *Manager) Update(interval time.Duration, files []string, externalLabels labels.Labels, externalURL string) error { 
  2.  m.mtx.Lock() 
  3.  defer m.mtx.Unlock() 
  4.     // 從當(dāng)前文件中加載規(guī)則 
  5.  groups, errs := m.LoadGroups(interval, externalLabels, externalURL, files...) 
  6.  if errs != nil { 
  7.   for _, e := range errs { 
  8.    level.Error(m.logger).Log("msg""loading groups failed""err", e) 
  9.   } 
  10.   return errors.New("error loading rules, previous rule set restored"
  11.  } 
  12.  m.restored = true 
  13.  
  14.  var wg sync.WaitGroup 
  15.    //循環(huán)遍歷規(guī)則組 
  16.  for _, newg := range groups { 
  17.   // If there is an old group with the same identifier, 
  18.   // check if new group equals with the old group, if yes then skip it. 
  19.   // If not equals, stop it and wait for it to finish the current iteration. 
  20.   // Then copy it into the new group
  21.   //根據(jù)新的rules.Group的信息獲取規(guī)則組名 
  22.   gn := GroupKey(newg.file, newg.name
  23.    //根據(jù)規(guī)則組名獲取到老的規(guī)則組并刪除原有的rules.Group實(shí)例 
  24.   oldg, ok := m.groups[gn] 
  25.   delete(m.groups, gn) 
  26.  
  27.   if ok && oldg.Equals(newg) { 
  28.    groups[gn] = oldg 
  29.    continue 
  30.   } 
  31.  
  32.   wg.Add(1) 
  33.     //為每一個(gè)rules.Group實(shí)例啟動(dòng)一個(gè)goroutine 
  34.   go func(newg *Group) { 
  35.    if ok { 
  36.     oldg.stop() 
  37.      //將老的規(guī)則組中的狀態(tài)信息復(fù)制到新的規(guī)則組 
  38.     newg.CopyState(oldg) 
  39.    } 
  40.    wg.Done() 
  41.    // Wait with starting evaluation until the rule manager 
  42.    // is told to run. This is necessary to avoid running 
  43.    // queries against a bootstrapping storage. 
  44.    <-m.block 
  45.      //調(diào)用rules.Group.run()方法,開(kāi)始周期性的執(zhí)行PromQl語(yǔ)句 
  46.    newg.run(m.opts.Context) 
  47.   }(newg) 
  48.  } 
  49.  
  50.  // Stop remaining old groups. 
  51.  //停止所有老規(guī)則組的服務(wù) 
  52.  wg.Add(len(m.groups)) 
  53.  for n, oldg := range m.groups { 
  54.   go func(n string, g *Group) { 
  55.    g.markStale = true 
  56.    g.stop() 
  57.    if m := g.metrics; m != nil { 
  58.     m.IterationsMissed.DeleteLabelValues(n) 
  59.     m.IterationsScheduled.DeleteLabelValues(n) 
  60.     m.EvalTotal.DeleteLabelValues(n) 
  61.     m.EvalFailures.DeleteLabelValues(n) 
  62.     m.GroupInterval.DeleteLabelValues(n) 
  63.     m.GroupLastEvalTime.DeleteLabelValues(n) 
  64.     m.GroupLastDuration.DeleteLabelValues(n) 
  65.     m.GroupRules.DeleteLabelValues(n) 
  66.     m.GroupSamples.DeleteLabelValues((n)) 
  67.    } 
  68.    wg.Done() 
  69.   }(n, oldg) 
  70.  } 
  71.  
  72.  wg.Wait() 
  73.     //更新規(guī)則管理器中的規(guī)則組 
  74.  m.groups = groups  
  75.  
  76.  return nil 

運(yùn)行Rule組調(diào)度方法

規(guī)則組啟動(dòng)流程(Group.run):進(jìn)入Group.run方法后先進(jìn)行初始化等待,以使規(guī)則的運(yùn)算時(shí)間在同一時(shí)刻,周期為g.interval;然后定義規(guī)則運(yùn)算調(diào)度方法:iter,調(diào)度周期為g.interval;在iter方法中調(diào)用g.Eval方法執(zhí)行下一層次的規(guī)則運(yùn)算調(diào)度。

規(guī)則運(yùn)算的調(diào)度周期g.interval,由prometheus.yml配置文件中g(shù)lobal中的 [ evaluation_interval:| default = 1m ]指定。實(shí)現(xiàn)如下:

  1. func (g *Group) run(ctx context.Context) { 
  2.  defer close(g.terminated) 
  3.  
  4.  // Wait an initial amount to have consistently slotted intervals. 
  5.  evalTimestamp := g.EvalTimestamp(time.Now().UnixNano()).Add(g.interval) 
  6.  select { 
  7.  case <-time.After(time.Until(evalTimestamp))://初始化等待 
  8.  case <-g.done: 
  9.   return 
  10.  } 
  11.  
  12.  ctx = promql.NewOriginContext(ctx, map[string]interface{}{ 
  13.   "ruleGroup": map[string]string{ 
  14.    "file": g.File(), 
  15.    "name": g.Name(), 
  16.   }, 
  17.  }) 
  18.     //定義規(guī)則組規(guī)則運(yùn)算調(diào)度算法 
  19.  iter := func() { 
  20.   g.metrics.IterationsScheduled.WithLabelValues(GroupKey(g.file, g.name)).Inc() 
  21.  
  22.   start := time.Now() 
  23.     //規(guī)則運(yùn)算的入口 
  24.   g.Eval(ctx, evalTimestamp) 
  25.   timeSinceStart := time.Since(start) 
  26.  
  27.   g.metrics.IterationDuration.Observe(timeSinceStart.Seconds()) 
  28.   g.setEvaluationTime(timeSinceStart) 
  29.   g.setLastEvaluation(start) 
  30.  } 
  31.  
  32.  // The assumption here is that since the ticker was started after having 
  33.  // waited for `evalTimestamp` to pass, the ticks will trigger soon 
  34.  // after each `evalTimestamp + N * g.interval` occurrence. 
  35.  tick := time.NewTicker(g.interval) //設(shè)置規(guī)則運(yùn)算定時(shí)器 
  36.  defer tick.Stop() 
  37.  
  38.  defer func() { 
  39.   if !g.markStale { 
  40.    return 
  41.   } 
  42.   go func(now time.Time) { 
  43.    for _, rule := range g.seriesInPreviousEval { 
  44.     for _, r := range rule { 
  45.      g.staleSeries = append(g.staleSeries, r) 
  46.     } 
  47.    } 
  48.    // That can be garbage collected at this point. 
  49.    g.seriesInPreviousEval = nil 
  50.    // Wait for 2 intervals to give the opportunity to renamed rules 
  51.    // to insert new series in the tsdb. At this point if there is a 
  52.    // renamed rule, it should already be started. 
  53.    select { 
  54.    case <-g.managerDone: 
  55.    case <-time.After(2 * g.interval): 
  56.     g.cleanupStaleSeries(ctx, now) 
  57.    } 
  58.   }(time.Now()) 
  59.  }() 
  60.     //調(diào)用規(guī)則組規(guī)則運(yùn)算的調(diào)度方法 
  61.  iter() 
  62.  if g.shouldRestore { 
  63.   // If we have to restore, we wait for another Eval to finish. 
  64.   // The reason behind this is, during first eval (or before it) 
  65.   // we might not have enough data scraped, and recording rules would not 
  66.   // have updated the latest valueson which some alerts might depend. 
  67.   select { 
  68.   case <-g.done: 
  69.    return 
  70.   case <-tick.C: 
  71.    missed := (time.Since(evalTimestamp) / g.interval) - 1 
  72.    if missed > 0 { 
  73.     g.metrics.IterationsMissed.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed)) 
  74.     g.metrics.IterationsScheduled.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed)) 
  75.    } 
  76.    evalTimestamp = evalTimestamp.Add((missed + 1) * g.interval) 
  77.    iter() 
  78.   } 
  79.  
  80.   g.RestoreForState(time.Now()) 
  81.   g.shouldRestore = false 
  82.  } 
  83.  
  84.  for { 
  85.   select { 
  86.   case <-g.done: 
  87.    return 
  88.   default
  89.    select { 
  90.    case <-g.done: 
  91.     return 
  92.    case <-tick.C: 
  93.     missed := (time.Since(evalTimestamp) / g.interval) - 1 
  94.     if missed > 0 { 
  95.      g.metrics.IterationsMissed.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed)) 
  96.      g.metrics.IterationsScheduled.WithLabelValues(GroupKey(g.file, g.name)).Add(float64(missed)) 
  97.     } 
  98.     evalTimestamp = evalTimestamp.Add((missed + 1) * g.interval) 
  99.      //調(diào)用規(guī)則組規(guī)則運(yùn)算的調(diào)度方法 
  100.     iter() 
  101.    } 
  102.   } 
  103.  } 

運(yùn)行Rule調(diào)度方法

規(guī)則組對(duì)具體規(guī)則的調(diào)度在Group.Eval中實(shí)現(xiàn),在Group.Eval方法中會(huì)將規(guī)則組下的每條規(guī)則通過(guò)QueryFunc將(promQL)放到查詢(xún)引擎(queryEngine)中執(zhí)行,如果被執(zhí)行的是AlertingRule類(lèi)型,那么執(zhí)行結(jié)果指標(biāo)會(huì)被NotifyFunc組件發(fā)送給告警服務(wù);如果是RecordingRule類(lèi)型,最后將改結(jié)果指標(biāo)存儲(chǔ)到Prometheus的儲(chǔ)存管理器中,并對(duì)過(guò)期指標(biāo)進(jìn)行存儲(chǔ)標(biāo)記處理。

  1. // Eval runs a single evaluation cycle in which all rules are evaluated sequentially. 
  2. func (g *Group) Eval(ctx context.Context, ts time.Time) { 
  3.  var samplesTotal float64 
  4.     遍歷當(dāng)前規(guī)則組下的所有規(guī)則 
  5.  for i, rule := range g.rules { 
  6.   select { 
  7.   case <-g.done: 
  8.    return 
  9.   default
  10.   } 
  11.  
  12.   func(i intrule Rule) { 
  13.    sp, ctx := opentracing.StartSpanFromContext(ctx, "rule"
  14.    sp.SetTag("name"rule.Name()) 
  15.    defer func(t time.Time) { 
  16.     sp.Finish() 
  17.       //更新服務(wù)指標(biāo)-規(guī)則的執(zhí)行時(shí)間 
  18.     since := time.Since(t) 
  19.     g.metrics.EvalDuration.Observe(since.Seconds()) 
  20.     rule.SetEvaluationDuration(since) 
  21.       //記錄本次規(guī)則執(zhí)行的耗時(shí) 
  22.     rule.SetEvaluationTimestamp(t) 
  23.    }(time.Now()) 
  24.      //記錄規(guī)則運(yùn)算的次數(shù) 
  25.    g.metrics.EvalTotal.WithLabelValues(GroupKey(g.File(), g.Name())).Inc() 
  26.      //運(yùn)算規(guī)則 
  27.    vector, err := rule.Eval(ctx, ts, g.opts.QueryFunc, g.opts.ExternalURL) 
  28.    if err != nil { 
  29.       //規(guī)則出現(xiàn)錯(cuò)誤后,終止查詢(xún) 
  30.     rule.SetHealth(HealthBad) 
  31.     rule.SetLastError(err) 
  32.      //記錄查詢(xún)失敗的次數(shù) 
  33.     g.metrics.EvalFailures.WithLabelValues(GroupKey(g.File(), g.Name())).Inc() 
  34.  
  35.     // Canceled queries are intentional termination of queries. This normally 
  36.     // happens on shutdown and thus we skip logging of any errors here. 
  37.     if _, ok := err.(promql.ErrQueryCanceled); !ok { 
  38.      level.Warn(g.logger).Log("msg""Evaluating rule failed""rule"rule"err", err) 
  39.     } 
  40.     return 
  41.    } 
  42.    samplesTotal += float64(len(vector)) 
  43.             //判斷是否是告警類(lèi)型規(guī)則 
  44.    if ar, ok := rule.(*AlertingRule); ok { 
  45.                 發(fā)送告警 
  46.     ar.sendAlerts(ctx, ts, g.opts.ResendDelay, g.interval, g.opts.NotifyFunc) 
  47.    } 
  48.    var ( 
  49.     numOutOfOrder = 0 
  50.     numDuplicates = 0 
  51.    ) 
  52.     //此處為Recording獲取存儲(chǔ)器指標(biāo) 
  53.    app := g.opts.Appendable.Appender(ctx) 
  54.    seriesReturned := make(map[string]labels.Labels, len(g.seriesInPreviousEval[i])) 
  55.    defer func() { 
  56.     if err := app.Commit(); err != nil { 
  57.      rule.SetHealth(HealthBad) 
  58.      rule.SetLastError(err) 
  59.      g.metrics.EvalFailures.WithLabelValues(GroupKey(g.File(), g.Name())).Inc() 
  60.  
  61.      level.Warn(g.logger).Log("msg""Rule sample appending failed""err", err) 
  62.      return 
  63.     } 
  64.     g.seriesInPreviousEval[i] = seriesReturned 
  65.    }() 
  66.  
  67.    for _, s := range vector { 
  68.     if _, err := app.Append(0, s.Metric, s.T, s.V); err != nil { 
  69.      rule.SetHealth(HealthBad) 
  70.      rule.SetLastError(err) 
  71.  
  72.      switch errors.Cause(err) { 
  73.                         儲(chǔ)存指標(biāo)返回的各種錯(cuò)誤碼處理 
  74.      case storage.ErrOutOfOrderSample: 
  75.       numOutOfOrder++ 
  76.       level.Debug(g.logger).Log("msg""Rule evaluation result discarded""err", err, "sample", s) 
  77.      case storage.ErrDuplicateSampleForTimestamp: 
  78.       numDuplicates++ 
  79.       level.Debug(g.logger).Log("msg""Rule evaluation result discarded""err", err, "sample", s) 
  80.      default
  81.       level.Warn(g.logger).Log("msg""Rule evaluation result discarded""err", err, "sample", s) 
  82.      } 
  83.     } else { 
  84.       //緩存規(guī)則運(yùn)算后的結(jié)果指標(biāo) 
  85.      seriesReturned[s.Metric.String()] = s.Metric 
  86.     } 
  87.    } 
  88.    if numOutOfOrder > 0 { 
  89.     level.Warn(g.logger).Log("msg""Error on ingesting out-of-order result from rule evaluation""numDropped", numOutOfOrder) 
  90.    } 
  91.    if numDuplicates > 0 { 
  92.     level.Warn(g.logger).Log("msg""Error on ingesting results from rule evaluation with different value but same timestamp""numDropped", numDuplicates) 
  93.    } 
  94.  
  95.    for metric, lset := range g.seriesInPreviousEval[i] { 
  96.     if _, ok := seriesReturned[metric]; !ok { 
  97.       //設(shè)置過(guò)期指標(biāo)的指標(biāo)值 
  98.      // Series no longer exposed, mark it stale. 
  99.      _, err = app.Append(0, lset, timestamp.FromTime(ts), math.Float64frombits(value.StaleNaN)) 
  100.      switch errors.Cause(err) { 
  101.      case nil: 
  102.      case storage.ErrOutOfOrderSample, storage.ErrDuplicateSampleForTimestamp: 
  103.       // Do not count these in logging, as this is expected if series 
  104.       // is exposed from a different rule
  105.      default
  106.       level.Warn(g.logger).Log("msg""Adding stale sample failed""sample", metric, "err", err) 
  107.      } 
  108.     } 
  109.    } 
  110.   }(i, rule
  111.  } 
  112.  if g.metrics != nil { 
  113.   g.metrics.GroupSamples.WithLabelValues(GroupKey(g.File(), g.Name())).Set(samplesTotal) 
  114.  } 
  115.  g.cleanupStaleSeries(ctx, ts) 

然后就是規(guī)則的具體執(zhí)行了,我們這里先只看AlertingRule的流程。首先看下AlertingRule的結(jié)構(gòu):

  1. // An AlertingRule generates alerts from its vector expression. 
  2. type AlertingRule struct { 
  3.     // The name of the alert. 
  4.     name string 
  5.     // The vector expression from which to generate alerts. 
  6.     vector parser.Expr 
  7.     // The duration for which a labelset needs to persist in the expression 
  8.     // output vector before an alert transitions from Pending to Firing state. 
  9.     holdDuration time.Duration 
  10.     // Extra labels to attach to the resulting alert sample vectors. 
  11.     labels labels.Labels 
  12.     // Non-identifying key/value pairs. 
  13.     annotations labels.Labels 
  14.     // External labels from the global config. 
  15.     externalLabels map[string]string 
  16.     // true if old state has been restored. We start persisting samples for ALERT_FOR_STATE 
  17.     // only after the restoration. 
  18.     restored bool 
  19.     // Protects the below. 
  20.     mtx sync.Mutex 
  21.     // Time in seconds taken to evaluate rule
  22.     evaluationDuration time.Duration 
  23.     // Timestamp of last evaluation of rule
  24.     evaluationTimestamp time.Time 
  25.     // The health of the alerting rule
  26.     health RuleHealth 
  27.     // The last error seen by the alerting rule
  28.     lastError error 
  29.     // A map of alerts which are currently active (Pending or Firing), keyed by 
  30.     // the fingerprint of the labelset they correspond to
  31.     active map[uint64]*Alert 
  32.     logger log.Logger 

這里比較重要的就是active字段了,它保存了執(zhí)行規(guī)則后需要進(jìn)行告警的資源,具體是否告警還要執(zhí)行一系列的邏輯來(lái)判斷是否滿(mǎn)足告警條件。具體執(zhí)行的邏輯如下:

  1. func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, externalURL *url.URL) (promql.Vector, error) { 
  2.     res, err := query(ctx, r.vector.String(), ts) 
  3.     if err != nil { 
  4.         r.SetHealth(HealthBad) 
  5.         r.SetLastError(err) 
  6.         return nil, err 
  7.     } 
  8.     // ...... 

這一步通過(guò)創(chuàng)建Manager時(shí)傳入的QueryFunc函數(shù)執(zhí)行規(guī)則配置中的expr表達(dá)式,然后得到返回的結(jié)果,這里的結(jié)果是滿(mǎn)足表達(dá)式的指標(biāo)的集合。比如配置的規(guī)則為:

  1. cpu_usage > 90 

那么查出來(lái)的結(jié)果可能是

  1. cpu_usage{instance="192.168.0.11"} 91 
  2. cpu_usage{instance="192.168.0.12"} 92 

然后遍歷查詢(xún)到的結(jié)果,根據(jù)指標(biāo)的標(biāo)簽生成一個(gè)hash值,然后判斷這個(gè)hash值是否之前已經(jīng)存在(即之前是否已經(jīng)有相同的指標(biāo)數(shù)據(jù)返回),如果是,則更新上次的value及annotations,如果不是,則創(chuàng)建一個(gè)新的alert并保存至該規(guī)則下的active alert列表中。然后遍歷規(guī)則的active alert列表,根據(jù)規(guī)則的持續(xù)時(shí)長(zhǎng)配置、alert的上次觸發(fā)時(shí)間、alert的當(dāng)前狀態(tài)、本次查詢(xún)alert是否依然存在等信息來(lái)修改alert的狀態(tài)。具體規(guī)則如下:

如果alert之前存在,但本次執(zhí)行時(shí)不存在

  • 狀態(tài)是StatePending或者本次檢查時(shí)間距離上次觸發(fā)時(shí)間超過(guò)15分鐘(15分鐘為寫(xiě)死的常量),則將該alert從active列表中刪除
  • 狀態(tài)不為StateInactive的alert修改為StateInactive

如果alert之前存在并且本次執(zhí)行仍然存在

  • alert的狀態(tài)是StatePending并且本次檢查距離上次觸發(fā)時(shí)間超過(guò)配置的for持續(xù)時(shí)長(zhǎng),那么狀態(tài)修改為StateFiring

其余情況修改alert的狀態(tài)為StatePending

上面那一步只是修改了alert的狀態(tài),但是并沒(méi)有真正執(zhí)行發(fā)送告警操作。下面才是真正要執(zhí)行告警操作:

  1. // 判斷規(guī)則是否是alert規(guī)則,如果是則發(fā)送告警信息(具體是否真正發(fā)送由ar.sendAlerts中的邏輯判斷) 
  2. if ar, ok := rule.(*AlertingRule); ok { 
  3.     ar.sendAlerts(ctx, ts, g.opts.ResendDelay, g.interval, g.opts.NotifyFunc) 
  4. // ....... 
  5. func (r *AlertingRule) sendAlerts(ctx context.Context, ts time.Time, resendDelay time.Duration, interval time.Duration, notifyFunc NotifyFunc) { 
  6.     alerts := []*Alert{} 
  7.     r.ForEachActiveAlert(func(alert *Alert) { 
  8.         if alert.needsSending(ts, resendDelay) { 
  9.             alert.LastSentAt = ts 
  10.             // Allow for two Eval or Alertmanager send failures. 
  11.             delta := resendDelay 
  12.             if interval > resendDelay { 
  13.                 delta = interval 
  14.             } 
  15.             alert.ValidUntil = ts.Add(4 * delta) 
  16.             anew := *alert 
  17.             alerts = append(alerts, &anew) 
  18.         } 
  19.     }) 
  20.     notifyFunc(ctx, r.vector.String(), alerts...) 
  21. func (a *Alert) needsSending(ts time.Time, resendDelay time.Duration) bool { 
  22.     if a.State == StatePending { 
  23.         return false 
  24.     } 
  25.     // if an alert has been resolved since the last send, resend it 
  26.     if a.ResolvedAt.After(a.LastSentAt) { 
  27.         return true 
  28.     } 
  29.     return a.LastSentAt.Add(resendDelay).Before(ts) 

概括一下以上邏輯就是:

  1. 如果alert的狀態(tài)是StatePending,則不發(fā)送告警
  2. 如果alert的已經(jīng)被解決,那么再次發(fā)送告警標(biāo)記該條信息已經(jīng)被解決
  3. 如果當(dāng)前時(shí)間距離上次發(fā)送告警的時(shí)間大于配置的重新發(fā)送延時(shí)時(shí)間(ResendDelay),則發(fā)送告警,否則不發(fā)送

以上就是prometheus的告警流程。學(xué)習(xí)這個(gè)流程主要是問(wèn)了能夠?qū)rometheus的rules相關(guān)的做二次開(kāi)發(fā)。我們可以修改LoadGroups()方法,讓其可以動(dòng)態(tài)側(cè)加載定義在mysql中定義的規(guī)則,動(dòng)態(tài)實(shí)現(xiàn)告警規(guī)則更新。

參考: 

《深入淺出prometheus原理、應(yīng)用、源碼與拓展詳解》

 

責(zé)任編輯:武曉燕 來(lái)源: 運(yùn)維開(kāi)發(fā)故事
相關(guān)推薦

2024-07-31 08:02:26

Prometheus服務(wù)器代碼

2023-03-26 08:41:37

2021-03-31 08:02:34

Prometheus 監(jiān)控運(yùn)維

2023-09-12 07:11:33

Prometheus聚合告警GPT

2021-02-18 15:36:13

PrometheusAlertmanageGrafana

2025-04-09 08:05:00

運(yùn)維告警Prometheus

2022-07-29 21:23:54

Grafana微服務(wù)

2025-01-17 09:54:54

2014-06-16 11:17:12

入侵檢測(cè)OSSEC日志分析

2023-04-20 07:12:33

夜鶯監(jiān)控夜鶯

2022-08-30 13:03:39

prometheusAlert

2020-12-30 05:34:25

監(jiān)控PrometheusGrafana

2022-09-04 17:53:20

Prometheus開(kāi)源

2023-11-24 16:57:53

2021-08-26 11:30:54

AlertManage阿里云

2025-03-05 07:00:00

Grafana可視化Kubernetes

2023-11-13 08:15:36

2025-01-21 11:18:46

2011-08-15 16:28:06

Cocoa內(nèi)存管理

2010-04-20 13:59:30

Oracle管理規(guī)則
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)