zoukankan      html  css  js  c++  java
  • Go语言开发Prometheus Exporter示例

    一、Prometheus中的基本概念
    Prometheus将所有数据存储为时间序列,这里先来了解一下prometheus中的一些基本概念

    指标名和标签
    每个时间序列都由指标名和一组键值对(也称为标签)唯一标识。

    metric的格式如下:

    <metric name>{<label name>=<label value>, ...}
    1
    例如:

    http_requests_total{host="192.10.0.1", method="POST", handler="/messages"}
    1
    http_requests_total是指标名;
    host、method、handler是三个标签(label),也就是三个维度;
    查询语句可以基于这些标签or维度进行过滤和聚合;
    指标类型
    Prometheus client库提供四种核心度量标准类型。注意是客户端。Prometheus服务端没有区分类型,将所有数据展平为无类型时间序列。

    1、 Counter:只增不减的累加指标

    Counter就是一个计数器,表示一种累积型指标,该指标只能单调递增或在重新启动时重置为零,例如,您可以使用计数器来表示所服务的请求数,已完成的任务或错误。

    2、 Gauge:可增可减的测量指标

    Gauge是最简单的度量类型,只有一个简单的返回值,可增可减,也可以set为指定的值。所以Gauge通常用于反映当前状态,比如当前温度或当前内存使用情况;当然也可以用于“可增加可减少”的计数指标。

    3、Histogram:自带buckets区间用于统计分布的直方图

    Histogram主要用于在设定的分布范围内(Buckets)记录大小或者次数。

    例如http请求响应时间:0-100ms、100-200ms、200-300ms、>300ms 的分布情况,Histogram会自动创建3个指标,分别为:

    事件发送的总次数<basename>_count:比如当前一共发生了2次http请求
    所有事件产生值的大小的总和<basename>_sum:比如发生的2次http请求总的响应时间为150ms
    事件产生的值分布在bucket中的次数<basename>_bucket{le="上限"}:比如响应时间0-100ms的请求1次,100-200ms的请求1次,其他的0次
    4、Summary:数据分布统计图

    Summary和Histogram类似,都可以统计事件发生的次数或者大小,以及其分布情况。

    Summary和Histogram都提供了对于事件的计数_count以及值的汇总_sum,因此使用_count,和_sum时间序列可以计算出相同的内容。

    同时Summary和Histogram都可以计算和统计样本的分布情况,比如中位数,n分位数等等。不同在于Histogram可以通过histogram_quantile函数在服务器端计算分位数。 而Sumamry的分位数则是直接在客户端进行定义。因此对于分位数的计算。 Summary在通过PromQL进行查询时有更好的性能表现,而Histogram则会消耗更多的资源。相对的对于客户端而言Histogram消耗的资源更少。

    作业和实例
    在Prometheus中,一个可以拉取数据的端点IP:Port叫做一个实例(instance),而具有多个相同类型实例的集合称作一个作业(job)

    - job: api-server
    - instance 1: 1.2.3.4:5670
    - instance 2: 1.2.3.4:5671
    - instance 3: 5.6.7.8:5670
    - instance 4: 5.6.7.8:5671
    1
    2
    3
    4
    5
    当Prometheus拉取指标数据时,会自动生成一些标签(label)用于区别抓取的来源:

    job:配置的作业名;
    instance:配置的实例名,若没有实例名,则是抓取的IP:Port。
    对于每一个实例(instance)的抓取,Prometheus会默认保存以下数据:

    up{job="<job>", instance="<instance>"}:如果实例是健康的,即可达,值为1,否则为0;
    scrape_duration_seconds{job="<job>", instance="<instance>"}:抓取耗时;
    scrape_samples_post_metric_relabeling{job="<job>", instance="<instance>"}:指标重新标记后剩余的样本数。
    scrape_samples_scraped{job="<job>", instance="<instance>"}:实例暴露的样本数
    该up指标对于监控实例健康状态很有用。

    二、最简单的Exporter
    当你安装好go的开发环境,并下载好Prometheus依赖包到vendor以后,就可以编译个最简单的Exporter,代码如下:

    package main

    import (
    "log"
    "net/http"
    "github.com/prometheus/client_golang/prometheus/promhttp"
    )

    func main() {
    http.Handle("/metrics", promhttp.Handler())
    log.Fatal(http.ListenAndServe(":8080", nil))
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    执行go build编译运行,然后访问http://127.0.0.1:8080/metrics就可以看到采集到的指标数据。

    这段代码仅仅通过http模块指定了一个路径/metrics,并将client_golang库中的promhttp.Handler()作为处理函数传递进去后,就可以获取指标数据了。这个最简单的 Exporter 内部其实是使用了一个默认的收集器NewGoCollector采集当前Go运行时的相关信息,比如go堆栈使用、goroutine数据等等。

    三、Demo Exporter的目录结构
    项目的目录结构如下:

    prometheus-exporter/
    |-- collector
    `-- vendor
    `-- github.com
    |-- beorn7
    |-- golang
    |-- matttproud
    `-- prometheus
    1
    2
    3
    4
    5
    6
    7
    8
    vendor是项目依赖的外部包
    collector实现一个采集器,用于采集指标数据
    四、代码实现
    包括以下几个主要的步骤。

    1、定义指标
    定义指标就是创建指标的描述符,通常把要采集的指标描述符放在一个结构体里:

    // 指标结构体
    type Metrics struct {
    metrics map[string]*prometheus.Desc
    mutex sync.Mutex
    }

    /**
    * 函数:newGlobalMetric
    * 功能:创建指标描述符
    */
    func newGlobalMetric(namespace string, metricName string, docString string, labels []string) *prometheus.Desc {
    return prometheus.NewDesc(namespace+"_"+metricName, docString, labels, nil)
    }


    /**
    * 工厂方法:NewMetrics
    * 功能:初始化指标信息,即Metrics结构体
    */
    func NewMetrics(namespace string) *Metrics {
    return &Metrics{
    metrics: map[string]*prometheus.Desc{
    "my_counter_metric": newGlobalMetric(namespace, "my_counter_metric", "The description of my_counter_metric", []string{"host"}),
    "my_gauge_metric": newGlobalMetric(namespace, "my_gauge_metric","The description of my_gauge_metric", []string{"host"}),
    },
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    调用工厂方法即可创建一个结构体的实例

    2、注册指标
    metrics := collector.NewMetrics(*metricsNamespace) // 创建指标结构体实例
    registry := prometheus.NewRegistry()
    registry.MustRegister(metrics) // 注册指标
    1
    2
    3
    3、数据采集
    数据采集需要实现collector的两个接口:

    /**
    * 接口:Describe
    * 功能:传递结构体中的指标描述符到channel
    */
    func (c *Metrics) Describe(ch chan<- *prometheus.Desc) {
    for _, m := range c.metrics {
    ch <- m
    }
    }

    /**
    * 接口:Collect
    * 功能:抓取最新的数据,传递给channel
    */
    func (c *Metrics) Collect(ch chan<- prometheus.Metric) {
    c.mutex.Lock() // 加锁
    defer c.mutex.Unlock()

    mockCounterMetricData, mockGaugeMetricData := c.GenerateMockData()
    for host, currentValue := range mockCounterMetricData {
    ch <-prometheus.MustNewConstMetric(c.metrics["my_counter_metric"], prometheus.CounterValue, float64(currentValue), host)
    }
    for host, currentValue := range mockGaugeMetricData {
    ch <-prometheus.MustNewConstMetric(c.metrics["my_gauge_metric"], prometheus.GaugeValue, float64(currentValue), host)
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    4、启动HTTP服务
    http.Handle(*metricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
    http.ListenAndServe(":"+*listenAddr, nil)
    1
    2
    PS:这只是一个Demo,当实际需要开发一个exporter时,你需要重新定义要抓取的指标,并添加采集数据的具体逻辑。

    Demo代码:https://github.com/SongLee24/prometheus-exporter

    参考:
    1. https://prometheus.io/docs/concepts/metric_types/
    2. http://dockone.io/article/3298
    3. https://blog.csdn.net/u014029783/article/details/80001251
    ————————————————
    版权声明:本文为CSDN博主「神奕」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/lisonglisonglisong/article/details/81743555

  • 相关阅读:
    《JavaScript高级程序设计》笔记:客户端检测(九)
    《JavaScript高级程序设计》笔记:BOM(八)
    《JavaScript高级程序设计》笔记:函数表达式(七)
    《JavaScript高级程序设计》笔记:面向对象的程序设计(六)
    小tips:JS的Truthy和Falsy(真值与假值)
    footer固定在页面底部的实现方法总结
    WEB前端需要了解的XML相关基础知识
    vuex最简单、最直白、最全的入门文档
    原生JS替代jQuery的各种方法汇总
    数据挖掘优秀工具对比
  • 原文地址:https://www.cnblogs.com/ExMan/p/15067578.html
Copyright © 2011-2022 走看看