Prometheus自定义远端存储实现
前言
prometheus默认把数据存在本地文件,随着时间的增长,文件会越来越大,当查询一个时间跨度很大指标时,会很消耗资源,查询效率会很低。
为此prometheus引入了远端存储。为了适应不同的远端存储,prometheus并没有选择对接各种存储,而是定义了一套读写存储接口,并引入了Adapter适配器,将prometheus的读写请求转化为第三方远端存储接口,从而完成数据读写。整体架构如下图:
远端接口规范
prometheus源码里提供了influxdb的远程读写实现,具体代码在
documentation/examples/remote_storage/remote_storage_adapter目录下,可以自己去看下,这里只讲下实现原理。
写接口
比如现在上报了一个指标:
df{instance="localhost:5000",job="prometheus",mount="/boot",step="15s"}
prometheus在向远端存储发起写请求时,都是采用HTTP的形式发送数据,数据格式如下:
{
"timeseries": [{
"labels": [{
"name": "__name__",
"value": "df"
}, {
"name": "instance",
"value": "localhost:5000"
}, {
"name": "job",
"value": "prometheus"
}, {
"name": "mount",
"value": "/home"
}, {
"name": "step",
"value": "15s"
}],
"samples": [{
"value": 6,
"timestamp": 1632204968206
}]
}]
}
适配器的写接口要做的就是把这个json格式的数据 写到我们自己的存储里。
读接口
现在我要查询一个指标:
df{mount="/boot"}
prometheus在调用远程存储的读接口时,会传入以下格式的参数:
{
"queries": [{
"start_timestamp_ms": 1632208558163,
"end_timestamp_ms": 1632208858163,
"matchers": [{
"name": "mount",
"value": "/boot"
}, {
"name": "__name__",
"value": "df"
}],
"hints": {
"start_ms": 1632208558163,
"end_ms": 1632208858163
}
}]
}
再比如查询topk:
topk(3, rate(df[1m]))
对应的传参如下:
{
"queries": [{
"start_timestamp_ms": 1632216783085,
"end_timestamp_ms": 1632217083085,
"matchers": [{
"name": "__name__",
"value": "df"
}],
"hints": {
"func": "rate",
"start_ms": 1632217023085,
"end_ms": 1632217083085,
"range_ms": 60000
}
}]
}
而prometheus期望接口返回的数据格式如下:
{
"results": [{
"timeseries": [{
"labels": [{
"name": "instance",
"value": "localhost:5000"
}, {
"name": "job",
"value": "prometheus"
}, {
"name": "mount",
"value": "/boot"
}, {
"name": "step",
"value": "15s"
}, {
"name": "__name__",
"value": "df"
}],
"samples": [{
"value": 6,
"timestamp": 1632208920000
}, {
"value": 4,
"timestamp": 1632208950000
}, {
"value": 10,
"timestamp": 1632208980000
}, {
"value": 10,
"timestamp": 1632209010000
}, {
"value": 1,
"timestamp": 1632209040000
}, {
"value": 9,
"timestamp": 1632209070000
}]
}]
}]
}
Demo
open-falcon是小米公司开源的一款监控工具,其后端采用rrd存储,rrd是一个时序数据库,以文件的形式存储在硬盘中,其特定为一个指标对应一个rrd文件,rrd文件固定大小为100kb左右,因为它采取了预聚合的方式,无论数据存多久,rrd文件大小都是固定不变的,在查询时间跨度很大的情况下,它会自动根据查询时间范围来选择聚合策略将数据返回给用户。
示例代码在 https://gitee.com/zqwlai/prometheus/tree/falcon-adapter/documentation/examples/remote_storage/falcon-adapter ,有兴趣的同学可以看下。
主要逻辑就是写数据时对接open-falcon的transfer模块,将数据写入,查询数据时从open-falcon的api模块获取。
总结
适配器的实现原理就是把prometheus的上报数据转换为远端存储自己的格式,读取数据时再把远端存储的数据转换为prometheus期望的数据格式。