如何遠端寫入prometheus儲存
導讀 | prometheus一般都是採用pull方式獲取資料,但是有一些情況下,不方便配置exporter,就希望能透過push的方式上傳指標資料。 |
prometheus一般都是採用pull方式獲取資料,但是有一些情況下,不方便配置exporter,就希望能透過push的方式上傳指標資料。
1、可以採用pushgateway的方式,推送到pushgateway,然後prometheus透過pushgateway拉取資料。
2、在新版本中增加了一個引數:--enable-feature=remote-write-receiver,允許遠端透過介面/api/v1/write,直接寫資料到prometheus裡面。
pushgateway在高併發的情況下還是比較消耗資源的,特別是開啟一致性檢查,高併發寫入的時候特別慢。
第二種方式少了一層轉發,速度應該比較快。
可以透過prometheus的http介面/api/v1/write提交資料,這個介面的資料格式有有要求:
使用POST方式提交
需要經過protobuf編碼,依賴github.com/gogo/protobuf/proto
可以使用snappy進行壓縮,依賴github.com/golang/snappy
收集指標名稱,時間戳,值和標籤
將資料轉換成prometheus需要的資料格式
使用proto對資料進行編碼,並用snappy進行壓縮
透過httpClient提交資料
package prome import ( "bufio" "bytes" "context" "io" "io/ioutil" "net/http" "net/url" "regexp" "time" "github.com/gogo/protobuf/proto" "github.com/golang/snappy" "github.com/opentracing-contrib/go-stdlib/nethttp" opentracing "github.com/opentracing/opentracing-go" "github.com/pkg/errors" "github.com/prometheus/common/model" "github.com/prometheus/prometheus/pkg/labels" "github.com/prometheus/prometheus/prompb" ) type RecoverableError struct { error } type HttpClient struct { url *url.URL Client *http.Client timeout time.Duration } var MetricNameRE = regexp.MustCompile(`^[a-zA-Z_:][a-zA-Z0-9_:]*$`) type MetricPoint struct { Metric string `json:"metric"` // 指標名稱 TagsMap map[string]string `json:"tags"` // 資料標籤 Time int64 `json:"time"` // 時間戳,單位是秒 Value float64 `json:"value"` // 內部欄位,最終轉換之後的float64數值 } func (c *HttpClient) remoteWritePost(req []byte) error { httpReq, err := http.NewRequest("POST", c.url.String(), bytes.NewReader(req)) if err != nil { return err } httpReq.Header.Add("Content-Encoding", "snappy") httpReq.Header.Set("Content-Type", "application/x-protobuf") httpReq.Header.Set("User-Agent", "opcai") httpReq.Header.Set("X-Prometheus-Remote-Write-Version", "0.1.0") ctx, cancel := context.WithTimeout(context.Background(), c.timeout) defer cancel() httpReq = httpReq.WithContext(ctx) if parentSpan := opentracing.SpanFromContext(ctx); parentSpan != nil { var ht *nethttp.Tracer httpReq, ht = nethttp.TraceRequest( parentSpan.Tracer(), httpReq, nethttp.OperationName("Remote Store"), nethttp.ClientTrace(false), ) defer ht.Finish() } httpResp, err := c.Client.Do(httpReq) if err != nil { // Errors from Client.Do are from (for example) network errors, so are // recoverable. return RecoverableError{err} } defer func() { io.Copy(ioutil.Discard, httpResp.Body) httpResp.Body.Close() }() if httpResp.StatusCode/100 != 2 { scanner := bufio.NewScanner(io.LimitReader(httpResp.Body, 512)) line := "" if scanner.Scan() { line = scanner.Text() } err = errors.Errorf("server returned HTTP status %s: %s", httpResp.Status, line) } if httpResp.StatusCode/100 == 5 { return RecoverableError{err} } return err } func buildWriteRequest(samples []*prompb.TimeSeries) ([]byte, error) { req := &prompb.WriteRequest{ Timeseries: samples, } data, err := proto.Marshal(req) if err != nil { return nil, err } compressed := snappy.Encode(nil, data) return compressed, nil } type sample struct { labels labels.Labels t int64 v float64 } const ( LABEL_NAME = "__name__" ) func convertOne(item *MetricPoint) (*prompb.TimeSeries, error) { pt := prompb.TimeSeries{} pt.Samples = []prompb.Sample{{}} s := sample{} s.t = item.Time s.v = item.Value // name if !MetricNameRE.MatchString(item.Metric) { return &pt, errors.New("invalid metrics name") } nameLs := labels.Label{ Name: LABEL_NAME, Value: item.Metric, } s.labels = append(s.labels, nameLs) for k, v := range item.TagsMap { if model.LabelNameRE.MatchString(k) { ls := labels.Label{ Name: k, Value: v, } s.labels = append(s.labels, ls) } } pt.Labels = labelsToLabelsProto(s.labels, pt.Labels) // 時間賦值問題,使用毫秒時間戳 tsMs := time.Unix(s.t, 0).UnixNano() / 1e6 pt.Samples[0].Timestamp = tsMs pt.Samples[0].Value = s.v return &pt, nil } func labelsToLabelsProto(labels labels.Labels, buf []*prompb.Label) []*prompb.Label { result := buf[:0] if cap(buf) < len(labels) { result = make([]*prompb.Label, 0, len(labels)) } for _, l := range labels { result = append(result, &prompb.Label{ Name: l.Name, Value: l.Value, }) } return result } func (c *HttpClient) RemoteWrite(items []MetricPoint) (err error) { if len(items) == 0 { return } ts := make([]*prompb.TimeSeries, len(items)) for i := range items { ts[i], err = convertOne(&items[i]) if err != nil { return } } data, err := buildWriteRequest(ts) if err != nil { return } err = c.remoteWritePost(data) return } func NewClient(ur string, timeout time.Duration) (c *HttpClient, err error) { u, err := url.Parse(ur) if err != nil { return } c = &HttpClient{ url: u, Client: &http.Client{}, timeout: timeout, } return }
prometheus啟動的時候記得加引數--enable-feature=remote-write-receiver
package prome import ( "testing" "time" ) func TestRemoteWrite(t *testing.T) { c, err := NewClient("*time.Second) if err != nil { t.Fatal(err) } metrics := []MetricPoint{ {Metric: "opcai1", TagsMap: map[string]string{"env": "testing", "op": "opcai"}, Time: time.Now().Add(-1 * time.Minute).Unix(), Value: 1}, {Metric: "opcai2", TagsMap: map[string]string{"env": "testing", "op": "opcai"}, Time: time.Now().Add(-2 * time.Minute).Unix(), Value: 2}, {Metric: "opcai3", TagsMap: map[string]string{"env": "testing", "op": "opcai"}, Time: time.Now().Unix(), Value: 3}, {Metric: "opcai4", TagsMap: map[string]string{"env": "testing", "op": "opcai"}, Time: time.Now().Unix(), Value: 4}, } err = c.RemoteWrite(metrics) if err != nil { t.Fatal(err) } t.Log("end...") }
使用go test進行測試
go test -v
這個方法也是在看夜鶯v5的程式碼的時候發現的,剛好有需要統一收集redis的監控指標,剛好可以用上,之前用pushgateway寫的實在是慢。
原文來自:
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69955379/viewspace-2784530/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 如何從Maven遠端儲存庫下載?Maven
- win10 mstsc怎麼儲存遠端密碼_win10 mstsc如何儲存遠端密碼Win10密碼
- Prometheus TSDB儲存原理Prometheus
- MySQL 遠端連線(federated儲存引擎)MySql儲存引擎
- 如何精簡 Prometheus 的指標和儲存佔用Prometheus指標
- NAS儲存外網遠端訪問的方式
- win10系統遠端桌面如何儲存密碼【圖文】Win10密碼
- 在客戶端儲存對EJB的遠端呼叫是否可行?客戶端
- 如何遠端登入Windows系統?Windows
- php獲取遠端網站圖片並儲存本地PHP網站
- ASP儲存遠端圖片檔案到原生程式碼
- MySQL的寫入資料儲存過程MySql儲存過程
- 如何遠端登入Linux系統?Linux
- Win2k"秘密武器"之遠端儲存分析(轉)
- 在遠端和本地儲存過程間傳遞陣列儲存過程陣列
- 移動端的資料輸入與儲存
- 大小端儲存模式模式
- win10系統遠端桌面儲存登入密碼後無法修改怎麼辦Win10密碼
- 本地MinIO儲存服務Java遠端呼叫上傳檔案Java
- Win2k秘密武器之遠端儲存診斷(轉)
- 在遠端和本地儲存過程間傳遞陣列[zt]儲存過程陣列
- 兩招提升硬碟儲存資料的寫入效率硬碟
- Prometheus時序資料庫-磁碟中的儲存結構Prometheus資料庫
- 雲伺服器:如何遠端登入docker容器伺服器Docker
- 如何正確地把伺服器端返回的檔案二進位制流寫入到本地儲存成檔案伺服器
- 穀粒商城day61-商品服務-API-新增商品-儲存SPU基本資訊+儲存SKU基本資訊+呼叫遠端服務儲存優惠等資訊API
- SSH Exporter:基於Prometheus的遠端系統效能監控神器ExportPrometheus
- rd遠端桌面 如何連線rd遠端桌面
- win10遠端登入設定如何操作_win10遠端登入電腦怎麼設定Win10
- 客戶端儲存筆記客戶端筆記
- 客戶端儲存那些事客戶端
- InnoDB儲存引擎——兩次寫儲存引擎
- 編寫JAVA儲存過程Java儲存過程
- Gartner:浪潮儲存進入分散式儲存前三分散式
- 移動端長按儲存、取消長按儲存圖片
- SSH遠端登入原理
- sysdba不能遠端登入
- redis - 遠端登入指令Redis