支持remote write和exemplar的prometheus服務


最近項目組在做Prometheus指標采集和告警,其中用到了Prometheus的exemplar特性,由於該特性比較新,當前支持該特性的存儲有比較少。因此需要自行實現exemplar功能。

我在github上創建了一個代碼庫,內容如下:

功能支持列表

  • 支持從kafka消費Prometheus指標數據,數據使用protobuf編碼
  • 支持Prometheus exemplar功能
  • 支持exemplar的wal
  • 支持remote write指標到存儲

kafka消費端

本項目使用的是騰訊的cKafka

golang的kafka消費端需要用到github.com/confluentinc/confluent-kafka-go/kafka,使用該庫之前需要安裝librdkafka庫,但不支持在Windows系統上安裝librdkafka。安裝步驟如下:

git clone https://github.com/edenhill/librdkafka.gitcd librdkafka./configuremakesudo make install

環境上運行時可以考慮將librdkafka庫編譯到鏡像中。如使用Alpine鏡像時執行apk add librdkafka-dev pkgconf安裝即可。官方文檔中有提到,如果使用Alpine Linux ,編譯方式為:go build -tags musl ./...

Metrics的寫入

只需將metrics使用proto.Marshal編碼到promWR即可:

func (c *client) WriteRaw(
    ctx context.Context,
    promWR []byte,
    opts WriteOptions,
) (WriteResult, WriteError) {
    var result WriteResult
    encoded := snappy.Encode(nil, promWR)

    body := bytes.NewReader(encoded)
    req, err := http.NewRequest("POST", c.writeURL, body)
    if err != nil {
        return result, writeError{err: err}
    }

    req.Header.Set("Content-Type", "application/x-protobuf")
    req.Header.Set("Content-Encoding", "snappy")
    req.Header.Set("User-Agent", c.userAgent)
    req.Header.Set("X-Prometheus-Remote-Write-Version", "0.1.0")
    if opts.Headers != nil {
        for k, v := range opts.Headers {
            req.Header.Set(k, v)
        }
    }

    resp, err := c.httpClient.Do(req.WithContext(ctx))
    if err != nil {
        return result, writeError{err: err}
    }

    result.StatusCode = resp.StatusCode

    defer resp.Body.Close()

    if result.StatusCode/100 != 2 {
        writeErr := writeError{
            err:  fmt.Errorf("expected HTTP 200 status code: actual=%d", resp.StatusCode),
            code: result.StatusCode,
        }

        body, err := ioutil.ReadAll(resp.Body)
        if err != nil {
            writeErr.err = fmt.Errorf("%v, body_read_error=%s", writeErr.err, err)
            return result, writeErr
        }

        writeErr.err = fmt.Errorf("%v, body=%s", writeErr.err, body)
        return result, writeErr
    }

    return result, nil
}

metric的查詢

使用victoriametrics時,強烈建議同時部署grafana,使用grafana中的Explore功能來查找metrics。victoriametrics的vmselect組件自帶的UI很不方便。

鏡像編譯

如上所述,如果需要在需要Alpine Linux中進行編譯,則需要在在Dockerfile中添加如下內容:

RUN apk add git && apk add librdkafka-dev pkgconf && apk add build-base && apk add alpine-sdk

由於上述lib的安裝比較慢,為了加快安裝,可以將安裝了這些lib的鏡像作為基礎鏡像。

FROM golang:1.16.8-alpine3.14 as build
WORKDIR /app
RUN apk add git && apk add librdkafka-dev pkgconf && apk add build-base && apk add alpine-sdk
ENV http_proxy= GO111MODULE=on GOPROXY=https://goproxy.cn,direct GOPRIVATE=*.weimob.com

COPY go.mod .
COPY go.sum .
COPY . .

RUN cd cmd/ && GOOS=linux go build -tags musl -o ../prometheusWriter main.go

CMD ["/app/prometheusWriter"]

FROM alpine:latest
WORKDIR /app
RUN sed -i s/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g /etc/apk/repositories
RUN apk add tzdata
RUN ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime && echo "Asia/Shanghai" > /etc/timezone
COPY --from=build /app/prometheusWriter /app/
RUN chmod +x /app/prometheusWriter
COPY config.json /app/config.json
CMD ["/app/prometheusWriter"]

支持Exemplar

Exemplar的數據結構比較簡單,就是個ring buffer。

下面是使用curl命令進行查找的例子:

# curl  '127.0.0.1:8000' --header 'Content-Type: application/json' -d '{"start":"1632980302","end":"1632980402","query":"{testlabel11=\"test\"}"}' 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM