zoukankan      html  css  js  c++  java
  • prometheus+exporter小测试:

    1.golang中使用expoter

    import (
      "github.com/prometheus/client_golang/prometheus/promhttp"
    )
    
    func main(){
      http.Handle("/metrics", promhttp.Handler())
    }
    

    2.访问expoter内的数据

    curl -G "http://192.168.0.88:8080/metrics" > text.txt
    

    数据的格式如下:

    # HELP go_info Information about the Go environment.
    # TYPE go_info gauge
    go_info{version="go1.14.6"} 1
    

    也可以访问GZIP格式的数据:

    curl -G -H "User-Agent: Prometheus/2.28.1" -H "Accept: application/openmetrics-text; version=0.0.1,text/plain;version=0.0.4;q=0.5,*/*;q=0.1" -H "Accept-Encoding: gzip" -H "X-Prometheus-Scrape-Timeout-Seconds: 10" "http://192.168.0.88:8080/metrics" > 1.txt.gz
    gzip -d 1.txt.gz
    

    GZIP方式仍然是文本,但是压缩比很大。测试发现GZIP格式的体积只有文本格式的 15% !

    3.源码分析

    有几个疑问:存在一个很大的expoter——
    1.能不能分段拉取数据?
    2.能不能使用二进制格式来缩小体积?
    3.会不会在拉取的时候,造成内存暴涨?(在exporter的进程中构造好数据后再发送)

    3.1 http handle

    client_golang/prometheus/promhttp/http.go

    • 入口函数
    func Handler() http.Handler {
    	return InstrumentMetricHandler(
    		prometheus.DefaultRegisterer, HandlerFor(prometheus.DefaultGatherer, HandlerOpts{}),
    	)
    }
    
    • 在HandlerFor函数中提供处理代码
    func HandlerFor(reg prometheus.Gatherer, opts HandlerOpts) http.Handler{
      //...
      h := http.HandlerFunc(func(rsp http.ResponseWriter, req *http.Request) {
         //HTTP回调的主要逻辑
      })
    }
    
    • 根据请求header来决定输出什么格式:
    		var contentType expfmt.Format
    		if opts.EnableOpenMetrics {
    			contentType = expfmt.NegotiateIncludingOpenMetrics(req.Header)
    		} else {
    			contentType = expfmt.Negotiate(req.Header)
    		}
    
    • 从代码看来,只有三种格式,且都是文本格式(解释了第二个问题)
    func Negotiate(h http.Header) Format {
    	for _, ac := range goautoneg.ParseAccept(h.Get(hdrAccept)) {
    		ver := ac.Params["version"]
    		if ac.Type+"/"+ac.SubType == ProtoType && ac.Params["proto"] == ProtoProtocol {
    			switch ac.Params["encoding"] {
    			case "delimited":
    				return FmtProtoDelim
    			case "text":
    				return FmtProtoText
    			case "compact-text":
    				return FmtProtoCompact
    			}
    		}
    		if ac.Type == "text" && ac.SubType == "plain" && (ver == TextVersion || ver == "") {
    			return FmtText
    		}
    	}
    	return FmtText
    }
    
    • 输出部分的代码
    		for _, mf := range mfs {
    			if handleError(enc.Encode(mf)) {
    				return
    			}
    		}
    

    是一边读取一边输出的。

    • 解释了第三个问题:不会造成内存暴涨
    • 解释了第一个问题:逻辑上不支持分段去拉

    展望:

    1.尽量不要存在很大的expoter
    2.可以把proxy配置到一个很大的expoter上,然后每次拉取只返回一部分metric
    3.可以基于树来重新实现expoter的逻辑

  • 相关阅读:
    SGU180:Inversions(树状数组)
    Android布局中match_parent和fill_parent的差别
    上拉电阻和下拉电阻
    iOS应用性能调优的25个建议和技巧
    《拼音字母》 蓝桥杯复试试题
    构建轻量级的Table View注意事项[UIKit]
    Spark学习(一) 基本操作
    水滴状的自己定义视图,让您摆脱单调的Dialog
    【Scala】使用Option、Some、None,避免使用null
    基于tornado实现web camera
  • 原文地址:https://www.cnblogs.com/ahfuzhang/p/15120481.html
Copyright © 2011-2022 走看看