<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Prometheus時序數據庫-報警的計算

      Prometheus時序數據庫-報警的計算

      在前面的文章中,筆者詳細的闡述了Prometheus的數據插入存儲查詢等過程。但作為一個監控神器,報警計算功能是必不可少的。自然的Prometheus也提供了靈活強大的報警規則可以讓我們自由去發揮。在本篇文章里,筆者就帶讀者去看下Prometheus內部是怎么處理報警規則的。

      報警架構

      Prometheus只負責進行報警計算,而具體的報警觸發則由AlertManager完成。如果我們不想改動AlertManager以完成自定義的路由規則,還可以通過webhook外接到另一個系統(例如,一個轉換到kafka的程序)。

      在本篇文章里,筆者并不會去設計alertManager,而是專注于Prometheus本身報警規則的計算邏輯。

      一個最簡單的報警規則

      rules:
      	alert: HTTPRequestRateLow
      	expr: http_requests < 100
      	for: 60s
      	labels:
      		severity: warning
      	annotations:
      		description: "http request rate low"
      	
      

      這上面的規則即是http請求數量<100從持續1min,則我們開始報警,報警級別為warning

      什么時候觸發這個計算

      在加載完規則之后,Prometheus按照evaluation_interval這個全局配置去不停的計算Rules。代碼邏輯如下所示:

      rules/manager.go
      
      func (g *Group) run(ctx context.Context) {
      	iter := func() {
      		......
      		g.Eval(ctx,evalTimestamp)
      		......
      	}
      	// g.interval = evaluation_interval
      	tick := time.NewTicker(g.interval)
      	defer tick.Stop()
      	......
      	for {
      		......
      		case <-tick.C:
      			......
      			iter()
      	}
      }
      

      而g.Eval的調用為:

      func (g *Group) Eval(ctx context.Context, ts time.Time) {
      	// 對所有的rule
      	for i, rule := range g.rules {
      		......
      		// 先計算出是否有符合rule的數據
      		vector, err := rule.Eval(ctx, ts, g.opts.QueryFunc, g.opts.ExternalURL)
      		......
      		// 然后發送
      		ar.sendAlerts(ctx, ts, g.opts.ResendDelay, g.interval, g.opts.NotifyFunc)
      	}
      	......
      }
      

      整個過程如下圖所示:

      對單個rule的計算

      我們可以看到,最重要的就是rule.Eval這個函數。代碼如下所示:

      func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, externalURL *url.URL) (promql.Vector, error) {
      	// 最終調用了NewInstantQuery
      	res, err = query(ctx,r.vector.String(),ts)
      	......
      	// 報警組裝邏輯
      	......
      	// active 報警狀態變遷
      }
      

      這個Eval包含了報警的計算/組裝/發送的所有邏輯。我們先聚焦于最重要的計算邏輯。也就是其中的query。其實,這個query是對NewInstantQuery的一個簡單封裝。

      func EngineQueryFunc(engine *promql.Engine, q storage.Queryable) QueryFunc {
      	return func(ctx context.Context, qs string, t time.Time) (promql.Vector, error) {
      		q, err := engine.NewInstantQuery(q, qs, t)
      		......
      		res := q.Exec(ctx)
      	}
      }
      

      也就是說它執行了一個瞬時向量的查詢。而其查詢的表達式按照我們之前給出的報警規則,即是

      http_requests < 100 
      

      既然要計算表達式,那么第一步,肯定是將其構造成一顆AST。其樹形結構如下圖所示:

      解析出左節點是個VectorSelect而且知道了其lablelMatcher是

      __name__:http_requests
      

      那么我們就可以左節點VectorSelector進行求值。直接利用倒排索引在head中查詢即可(因為instant query的是當前時間,所以肯定在內存中)。

      想知道具體的計算流程,可以見筆者之前的博客《Prometheus時序數據庫-數據的查詢》
      計算出左節點的數據之后,我們就可以和右節點進行比較以計算出最終結果了。具體代碼為:

      func (ev *evaluator) eval(expr Expr) Value {
      	......
      	case *BinaryExpr:
      	......
      		case lt == ValueTypeVector && rt == ValueTypeScalar:
      			return ev.rangeEval(func(v []Value, enh *EvalNodeHelper) Vector {
      				return ev.VectorscalarBinop(e.Op, v[0].(Vector), Scalar{V: v[1].(Vector)[0].Point.V}, false, e.ReturnBool, enh)
      			}, e.LHS, e.RHS)
      	.......
      }
      

      最后調用的函數即為:

      func (ev *evaluator) VectorBinop(op ItemType, lhs, rhs Vector, matching *VectorMatching, returnBool bool, enh *EvalNodeHelper) Vector {
      	// 對左節點計算出來的所有的數據sample
      	for _, lhsSample := range lhs {
      		......
      		// 由于左邊lv = 75 < 右邊rv = 100,且op為less
      		/**
      			vectorElemBinop(){
      				case LESS
      					return lhs, lhs < rhs
      			}
      		**/
      		// 這邊得到的結果value=75,keep = true
      		value, keep := vectorElemBinop(op, lv, rv)
      		......
      		if keep {
      			......
      			// 這邊就講75放到了輸出里面,也就是說我們最后的計算確實得到了數據。
      			enh.out = append(enh.out.sample)
      		}
      	}
      }
      

      如下圖所示:

      最后我們的expr輸出即為

      sample {
      	Point {t:0,V:75}
      	Metric {__name__:http_requests,instance:0,job:api-server}
      		
      }
      

      報警狀態變遷

      計算過程講完了,筆者還稍微講一下報警的狀態變遷,也就是最開始報警規則中的rule中的for,也即報警持續for(規則中為1min),我們才真正報警。為了實現這種功能,這就需要一個狀態機了。筆者這里只闡述下從Pending(報警出現)->firing(真正發送)的邏輯。

      在之前的Eval方法里面,有下面這段

      func (r *AlertingRule) Eval(ctx context.Context, ts time.Time, query QueryFunc, externalURL *url.URL) (promql.Vector, error) {
      	for _, smpl := range res {
      	......
      			if alert, ok := r.active[h]; ok && alert.State != StateInactive {
      			alert.Value = smpl.V
      			alert.Annotations = annotations
      			continue
      		}
      		// 如果這個告警不在active map里面,則將其放入
      		// 注意,這里的hash依舊沒有拉鏈法,有極小概率hash沖突
      r.active[h] = &Alert{
      			Labels:      lbs,
      			Annotations: annotations,
      			ActiveAt:    ts,
      			State:       StatePending,
      			Value:       smpl.V,
      		}
      	}
      	......
      	// 報警狀態的變遷邏輯
      	for fp, a := range r.active {
      		// 如果當前r.active的告警已經不在剛剛計算的result里面了		if _, ok := resultFPs[fp]; !ok {
      			// 如果狀態是Pending待發送
      			if a.State == StatePending || (!a.ResolvedAt.IsZero() && ts.Sub(a.ResolvedAt) > resolvedRetention) {
      				delete(r.active, fp)
      			}
      			......
      			continue
      		}
      		// 對于已有的Active報警,如果其Active的時間>r.holdDuration,也就是for指定的
      		if a.State == StatePending && ts.Sub(a.ActiveAt) >= r.holdDuration {
      			// 我們將報警置為需要發送
      			a.State = StateFiring
      			a.FiredAt = ts
      		}
      		......
      	
      	}
      }
      

      上面代碼邏輯如下圖所示:

      總結

      Prometheus作為一個監控神器,給我們提供了各種各樣的遍歷。其強大的報警計算功能就是其中之一。了解其中告警的計算原理,才能讓我們更好的運用它。

      posted @ 2021-03-31 10:42  無毀的湖光-Al  閱讀(537)  評論(5)    收藏  舉報
      主站蜘蛛池模板: 99热国产成人最新精品| 狠狠久久五月综合色和啪| 亚洲国产成人精品无色码| 亚洲欧美高清在线精品一区二区| 久久青青草原亚洲AV无码麻豆| 亚洲www永久成人网站| 乱码午夜-极品国产内射| 国产精品毛片一区二区| 在线 欧美 中文 亚洲 精品| 永久免费观看美女裸体的网站| 夜夜添无码一区二区三区| 久久碰国产一区二区三区| 日韩精品亚洲国产成人av| 国产一区二区高潮视频| 亚洲中文字幕av无码区| 午夜福利日本一区二区无码| 人妻无码中文专区久久app| 丁香五月婷激情综合第九色| 非会员区试看120秒6次| 南汇区| 99热久久这里只有精品| 亚洲狠狠婷婷综合久久久| 国产视频一区二区三区麻豆| 亚洲精品综合一区二区三区在线| av鲁丝一区鲁丝二区鲁丝三区| 亚洲一区二区三区| 亚洲一区二区av高清| 久久综合综合久久综合| 艳妇乳肉豪妇荡乳av无码福利| 懂色AV| 日韩本精品一区二区三区| 国内自拍网红在线综合一区| 99国产欧美另类久久久精品| 亚洲欧美日韩国产精品一区二区| 国产麻豆放荡av激情演绎| 国产成人午夜福利在线播放| 彝良县| 日韩熟妇中文色在线视频| 久久国产自偷自免费一区| 公天天吃我奶躁我的在| 曲松县|