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就是一個計數器,表示一種累積型指標,該指標只能單調遞增或在從新啓動時重置爲零,例如,您可使用計數器來表示所服務的請求數,已完成的任務或錯誤。函數
Gauge是最簡單的度量類型,只有一個簡單的返回值,可增可減,也能夠set爲指定的值。因此Gauge一般用於反映當前狀態,好比當前溫度或當前內存使用狀況;固然也能夠用於「可增長可減小」的計數指標。post
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和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時,你須要從新定義要抓取的指標,並添加採集數據的具體邏輯。