Go語言開發Prometheus Exporter示例

1、Prometheus中的基本概念

Prometheus將全部數據存儲爲時間序列,這裏先來了解一下prometheus中的一些基本概念git

指標名和標籤
每一個時間序列都由指標名和一組鍵值對(也稱爲標籤)惟一標識。github

metric的格式以下:golang

<metric name>{<label name>=<label value>, ...}


例如:api

http_requests_total{host="192.10.0.1", method="POST", handler="/messages"}


http_requests_total是指標名;
host、method、handler是三個標籤(label),也就是三個維度;
查詢語句能夠基於這些標籤or維度進行過濾和聚合;
指標類型
Prometheus client庫提供四種核心度量標準類型。注意是客戶端。Prometheus服務端沒有區分類型,將全部數據展平爲無類型時間序列。服務器

一、 Counter:只增不減的累加指標

Counter就是一個計數器,表示一種累積型指標,該指標只能單調遞增或在從新啓動時重置爲零,例如,您可使用計數器來表示所服務的請求數,已完成的任務或錯誤。函數

二、 Gauge:可增可減的測量指標

Gauge是最簡單的度量類型,只有一個簡單的返回值,可增可減,也能夠set爲指定的值。因此Gauge一般用於反映當前狀態,好比當前溫度或當前內存使用狀況;固然也能夠用於「可增長可減小」的計數指標。post

三、Histogram:自帶buckets區間用於統計分佈的直方圖

Histogram主要用於在設定的分佈範圍內(Buckets)記錄大小或者次數。性能

例如http請求響應時間:0-100ms、100-200ms、200-300ms、>300ms 的分佈狀況,Histogram會自動建立3個指標,分別爲:ui

事件發送的總次數<basename>_count:好比當前一共發生了2次http請求
全部事件產生值的大小的總和<basename>_sum:好比發生的2次http請求總的響應時間爲150ms
事件產生的值分佈在bucket中的次數<basename>_bucket{le="上限"}:好比響應時間0-100ms的請求1次,100-200ms的請求1次,其餘的0次spa

四、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

當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指標對於監控實例健康狀態頗有用。

2、最簡單的Exporter
當你安裝好go的開發環境,並下載好Prometheus依賴包到vendor之後,就能夠編譯個最簡單的Exporter,代碼以下:

 1 package main
 2 
 3 import (
 4 "log"
 5 "net/http"
 6 "github.com/prometheus/client_golang/prometheus/promhttp"
 7 )
 8 
 9 func main() {
10 http.Handle("/metrics", promhttp.Handler())
11 log.Fatal(http.ListenAndServe(":8080", nil))
12 }

執行go build編譯運行,而後訪問http://127.0.0.1:8080/metrics就能夠看到採集到的指標數據。

這段代碼僅僅經過http模塊指定了一個路徑/metrics,並將client_golang庫中的promhttp.Handler()做爲處理函數傳遞進去後,就能夠獲取指標數據了。這個最簡單的 Exporter 內部實際上是使用了一個默認的收集器NewGoCollector採集當前Go運行時的相關信息,好比go堆棧使用、goroutine數據等等。

3、Demo Exporter的目錄結構
項目的目錄結構以下:

1 prometheus-exporter/
2 |-- collector
3 `-- vendor
4   `-- github.com
5     |-- beorn7
6     |-- golang
7     |-- matttproud
8     `-- prometheus

vendor是項目依賴的外部包

collector實現一個採集器,用於採集指標數據
4、代碼實現
包括如下幾個主要的步驟。

一、定義指標
定義指標就是建立指標的描述符,一般把要採集的指標描述符放在一個結構體裏:

// 指標結構體
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"}),
},
}
}

調用工廠方法便可建立一個結構體的實例

二、註冊指標

metrics := collector.NewMetrics(*metricsNamespace) // 建立指標結構體實例
registry := prometheus.NewRegistry()
registry.MustRegister(metrics) // 註冊指標

三、數據採集
數據採集須要實現collector的兩個接口:

 1 /**
 2 * 接口:Describe
 3 * 功能:傳遞結構體中的指標描述符到channel
 4 */
 5 func (c *Metrics) Describe(ch chan<- *prometheus.Desc) {
 6 for _, m := range c.metrics {
 7 ch <- m
 8 }
 9 }
10 
11 /**
12 * 接口:Collect
13 * 功能:抓取最新的數據,傳遞給channel
14 */
15 func (c *Metrics) Collect(ch chan<- prometheus.Metric) {
16 c.mutex.Lock() // 加鎖
17 defer c.mutex.Unlock()
18 
19 mockCounterMetricData, mockGaugeMetricData := c.GenerateMockData()
20 for host, currentValue := range mockCounterMetricData {
21 ch <-prometheus.MustNewConstMetric(c.metrics["my_counter_metric"], prometheus.CounterValue, float64(currentValue), host)
22 }
23 for host, currentValue := range mockGaugeMetricData {
24 ch <-prometheus.MustNewConstMetric(c.metrics["my_gauge_metric"], prometheus.GaugeValue, float64(currentValue), host)
25 }
26 }

四、啓動HTTP服務

http.Handle(*metricsPath, promhttp.HandlerFor(registry, promhttp.HandlerOpts{}))
http.ListenAndServe(":"+*listenAddr, nil)

這只是一個Demo,當實際須要開發一個exporter時,你須要從新定義要抓取的指標,並添加採集數據的具體邏輯。

相關文章
相關標籤/搜索