• 远程存储
    • Remote Write
    • Remote Read
      • 配置文件
    • 自定义Remote Storage Adaptor
    • 使用Influxdb作为Remote Storage

    远程存储

    Prometheus的本地存储设计可以减少其自身运维和管理的复杂度,同时能够满足大部分用户监控规模的需求。但是本地存储也意味着Prometheus无法持久化数据,无法存储大量历史数据,同时也无法灵活扩展和迁移。

    为了保持Prometheus的简单性,Prometheus并没有尝试在自身中解决以上问题,而是通过定义两个标准接口(remote_write/remote_read),让用户可以基于这两个接口对接将数据保存到任意第三方的存储服务中,这种方式在Promthues中称为Remote Storage。

    Remote Write

    用户可以在Prometheus配置文件中指定Remote Write(远程写)的URL地址,一旦设置了该配置项,Prometheus将采集到的样本数据通过HTTP的形式发送给适配器(Adaptor)。而用户则可以在适配器中对接外部任意的服务。外部服务可以是真正的存储系统,公有云的存储服务,也可以是消息队列等任意形式。

    Remote Write

    Remote Read

    如下图所示,Promthues的Remote Read(远程读)也通过了一个适配器实现。在远程读的流程当中,当用户发起查询请求后,Promthues将向remote_read中配置的URL发起查询请求(matchers,ranges),Adaptor根据请求条件从第三方存储服务中获取响应的数据。同时将数据转换为Promthues的原始样本数据返回给Prometheus Server。

    当获取到样本数据后,Promthues在本地使用PromQL对样本数据进行二次处理。

    注意:启用远程读设置后,只在数据查询时有效,对于规则文件的处理,以及Metadata API的处理都只基于Prometheus本地存储完成。

    Remote Read

    配置文件

    Prometheus配置文件中添加remote_write和remote_read配置,其中url用于指定远程读/写的HTTP服务地址。如果该URL启动了认证则可以通过basic_auth进行安全认证配置。对于https的支持需要设定tls_concig。proxy_url主要用于Prometheus无法直接访问适配器服务的情况下。

    remote_write和remote_write具体配置如下所示:

    1. remote_write:
    2. url: <string>
    3. [ remote_timeout: <duration> | default = 30s ]
    4. write_relabel_configs:
    5. [ - <relabel_config> ... ]
    6. basic_auth:
    7. [ username: <string> ]
    8. [ password: <string> ]
    9. [ bearer_token: <string> ]
    10. [ bearer_token_file: /path/to/bearer/token/file ]
    11. tls_config:
    12. [ <tls_config> ]
    13. [ proxy_url: <string> ]
    14. remote_read:
    15. url: <string>
    16. required_matchers:
    17. [ <labelname>: <labelvalue> ... ]
    18. [ remote_timeout: <duration> | default = 30s ]
    19. [ read_recent: <boolean> | default = false ]
    20. basic_auth:
    21. [ username: <string> ]
    22. [ password: <string> ]
    23. [ bearer_token: <string> ]
    24. [ bearer_token_file: /path/to/bearer/token/file ]
    25. [ <tls_config> ]
    26. [ proxy_url: <string> ]

    自定义Remote Storage Adaptor

    实现自定义Remote Storage需要用户分别创建用于支持remote_read和remote_write的HTTP服务。

    Remote Storage

    当前Prometheus中Remote Storage相关的协议主要通过以下proto文件进行定义:

    1. syntax = "proto3";
    2. package prometheus;
    3. option go_package = "prompb";
    4. import "types.proto";
    5. message WriteRequest {
    6. repeated prometheus.TimeSeries timeseries = 1;
    7. }
    8. message ReadRequest {
    9. repeated Query queries = 1;
    10. }
    11. message ReadResponse {
    12. // In same order as the request's queries.
    13. repeated QueryResult results = 1;
    14. }
    15. message Query {
    16. int64 start_timestamp_ms = 1;
    17. int64 end_timestamp_ms = 2;
    18. repeated prometheus.LabelMatcher matchers = 3;
    19. }
    20. message QueryResult {
    21. // Samples within a time series must be ordered by time.
    22. repeated prometheus.TimeSeries timeseries = 1;
    23. }

    以下代码展示了一个简单的remote_write服务,创建用于接收remote_write的HTTP服务,将请求内容转换成WriteRequest后,用户就可以按照自己的需求进行后续的逻辑处理。

    1. package main
    2. import (
    3. "fmt"
    4. "io/ioutil"
    5. "net/http"
    6. "github.com/gogo/protobuf/proto"
    7. "github.com/golang/snappy"
    8. "github.com/prometheus/common/model"
    9. "github.com/prometheus/prometheus/prompb"
    10. )
    11. func main() {
    12. http.HandleFunc("/receive", func(w http.ResponseWriter, r *http.Request) {
    13. compressed, err := ioutil.ReadAll(r.Body)
    14. if err != nil {
    15. http.Error(w, err.Error(), http.StatusInternalServerError)
    16. return
    17. }
    18. reqBuf, err := snappy.Decode(nil, compressed)
    19. if err != nil {
    20. http.Error(w, err.Error(), http.StatusBadRequest)
    21. return
    22. }
    23. var req prompb.WriteRequest
    24. if err := proto.Unmarshal(reqBuf, &req); err != nil {
    25. http.Error(w, err.Error(), http.StatusBadRequest)
    26. return
    27. }
    28. for _, ts := range req.Timeseries {
    29. m := make(model.Metric, len(ts.Labels))
    30. for _, l := range ts.Labels {
    31. m[model.LabelName(l.Name)] = model.LabelValue(l.Value)
    32. }
    33. fmt.Println(m)
    34. for _, s := range ts.Samples {
    35. fmt.Printf(" %f %d\n", s.Value, s.Timestamp)
    36. }
    37. }
    38. })
    39. http.ListenAndServe(":1234", nil)
    40. }

    使用Influxdb作为Remote Storage

    目前Prometheus社区也提供了部分对于第三方数据库的Remote Storage支持:

    存储服务 支持模式
    AppOptics write
    Chronix write
    Cortex: read/write
    CrateDB read/write
    Gnocchi write
    Graphite write
    InfluxDB read/write
    OpenTSDB write
    PostgreSQL/TimescaleDB: read/write
    SignalFx write

    这里将介绍如何使用Influxdb作为Prometheus的Remote Storage,从而确保当Prometheus发生宕机或者重启之后能够从Influxdb中恢复和获取历史数据。

    这里使用docker-compose定义并启动Influxdb数据库服务,docker-compose.yml定义如下:

    1. version: '2'
    2. services:
    3. influxdb:
    4. image: influxdb:1.3.5
    5. command: -config /etc/influxdb/influxdb.conf
    6. ports:
    7. - "8086:8086"
    8. environment:
    9. - INFLUXDB_DB=prometheus
    10. - INFLUXDB_ADMIN_ENABLED=true
    11. - INFLUXDB_ADMIN_USER=admin
    12. - INFLUXDB_ADMIN_PASSWORD=admin
    13. - INFLUXDB_USER=prom
    14. - INFLUXDB_USER_PASSWORD=prom

    启动influxdb服务

    1. $ docker-compose up -d
    2. $ docker ps
    3. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    4. 795d0ead87a1 influxdb:1.3.5 "/entrypoint.sh -c..." 3 hours ago Up 3 hours 0.0.0.0:8086->8086/tcp localhost_influxdb_1

    获取并启动Prometheus提供的Remote Storage Adapter:

    1. go get github.com/prometheus/prometheus/documentation/examples/remote_storage/remote_storage_adapter

    获取remote_storage_adapter源码后,go会自动把相关的源码编译成可执行文件,并且保存在$GOPATH/bin/目录下。

    启动remote_storage_adapter并且设置Influxdb相关的认证信息:

    1. INFLUXDB_PW=prom $GOPATH/bin/remote_storage_adapter -influxdb-url=http://localhost:8086 -influxdb.username=prom -influxdb.database=prometheus -influxdb.retention-policy=autogen

    修改prometheus.yml添加Remote Storage相关的配置内容:

    1. remote_write:
    2. - url: "http://localhost:9201/write"
    3. remote_read:
    4. - url: "http://localhost:9201/read"

    重新启动Prometheus能够获取数据后,登录到influxdb容器,并验证数据写入。如下所示,当数据能够正常写入Influxdb后可以看到Prometheus相关的指标。

    1. docker exec -it 795d0ead87a1 influx
    2. Connected to http://localhost:8086 version 1.3.5
    3. InfluxDB shell version: 1.3.5
    4. > auth
    5. username: prom
    6. password:
    7. > use prometheus
    8. > SHOW MEASUREMENTS
    9. name: measurements
    10. name
    11. ----
    12. go_gc_duration_seconds
    13. go_gc_duration_seconds_count
    14. go_gc_duration_seconds_sum
    15. go_goroutines
    16. go_info
    17. go_memstats_alloc_bytes
    18. go_memstats_alloc_bytes_total
    19. go_memstats_buck_hash_sys_bytes
    20. go_memstats_frees_total
    21. go_memstats_gc_cpu_fraction
    22. go_memstats_gc_sys_bytes
    23. go_memstats_heap_alloc_bytes
    24. go_memstats_heap_idle_bytes

    当数据写入成功后,停止Prometheus服务。同时删除Prometheus的data目录,模拟Promthues数据丢失的情况后重启Prometheus。打开Prometheus UI如果配置正常,Prometheus可以正常查询到本地存储以删除的历史数据记录。

    从Remote Storage获取历史数据