本项目是PromQL转InfluxQL转译器和适配器,实现了传入原生PromQL查询语句,转成InfluxQL语句,并查询InfluxDB数据库返回结果。
- 前置条件
- 项目状态
- 特性说明
- 截图
- 应用场景
- 项目结构
- UML类图
- Prometheus数据写入InfluxDB格式转换
- 查询结果数据格式
- 使用方式
- 如何扩展
- TODO
- 其他说明
- Credits
- License
本程序基于以下前置条件开发:
- 基础设施版本:
- Prometheus v2.41.0:Docker镜像 prom/prometheus:v2.41.0
- InfluxDB v1.8.10:Docker镜像 influxdb:1.8.10
- Prometheus数据写入方式:
项目结构和核心代码基本稳定,后续开发以新增特性和性能优化为主,尽量兼容旧版本API。v1.0版本之前不建议用于生产环境。
- 支持Prometheus四种指标类型:Counter、Gauge、Histogram和Summary。
- 支持PromQL的7种选择器表达式、10种聚合操作表达式、13种二元操作表达式、24种内置函数转译到InfluxQL查询语句。
- 支持作为Prometheus数据源的适配器服务接入Grafana,输入PromQL查询语句实际由适配器服务向InfluxDB实例发起查询请求和返回结果。
- 既可以作为第三方库在你的项目中依赖,也可以作为微服务单独部署。
- 遵循SOLID软件设计原则,采用面向微服务架构的代码组织结构,易扩展。
截图中的dashboard来自Go Metrics。有部分PromQL函数和表达式未支持,所以有个别图没有数据。后续版本都会支持到。
原dashboard是针对部署在Kubernetes平台的应用的,作者修改了原dashboard里的查询标签。修改后的dashboard的存放在applications/prom/promethues_influxdb_grafana_stack/grafana/provisioning/dashboards/Go Metrics-1673758370201.json
路径下。
如果你想用InfluxDB作为时序数据的底层存储,同时又希望能继续使用Prometheus的PromQL查询语句做数据分析,可以采用本项目applications
模块下的prom
适配服务替换掉Prometheus的接口服务,仅将Prometheus用作监控数据采集服务。
本项目采用单仓库多模块的项目结构开发。包含:
applications
模块:负责提供适配层RESTful接口服务prom
模块:负责提供适配Grafana的Prometheus数据源的RESTful接口服务
adaptors
模块:负责提供各种适配器和转译器
.
├── LICENSE
├── README.md
├── adaptors # 负责提供各种适配器和转译器
│ ├── coverage.out
│ ├── go.mod
│ ├── go.sum
│ ├── prom # PromQL相关适配器和转译器
│ │ ├── influxdb # PromQL转InfluxQL,适配InfluxDB数据源
│ │ ├── influxdbadaptor.go # InfluxDB适配器
│ │ ├── influxdbadaptor_test.go
│ │ └── testdata
│ └── storages # 数据源相关的结构体
│ └── influxdb
├── applications # 负责提供适配层RESTful接口服务
│ ├── constants.go
│ ├── go.mod
│ ├── prom # 适配Grafana的Prometheus数据源的RESTful接口服务
│ │ ├── Dockerfile
│ │ ├── client
│ │ ├── cmd
│ │ ├── config
│ │ ├── db
│ │ ├── docker-compose.yml
│ │ ├── dto
│ │ ├── go.mod
│ │ ├── go.sum
│ │ ├── helper.go
│ │ ├── prom_openapi3.go
│ │ ├── prom_openapi3.json
│ │ ├── promethues_influxdb_grafana_stack
│ │ ├── svc.go
│ │ ├── svcimpl.go
│ │ ├── svcimpl_test.go
│ │ └── transport
│ └── prom.go # 需要适配器实现的接口
├── architecture.png
├── coverage.out
├── promql2influxql.png
├── screencapture-go-metrics-2023-01-12-16_37_22.png
├── screencapture-node-exporter-full-2023-01-12-16_41_13.pdf
└── uml.png
15 directories, 26 files
# Prometheus metric
example_metric{queue="0:http://example:8086/api/v1/prom/write?db=prometheus",le="0.005"} 308
# Same metric parsed into InfluxDB
measurement
example_metric
tags
queue = "0:http://example:8086/api/v1/prom/write?db=prometheus"
le = "0.005"
job = "prometheus"
instance = "localhost:9090"
__name__ = "example_metric"
fields
value = 308
{
"resultType": "vector",
"result": [
{
"metric": {
"container": "alertmanager",
"endpoint": "web",
"instance": "172.17.0.4:9093",
"job": "alertmanager-main",
"namespace": "monitoring",
"pod": "alertmanager-main-0",
"service": "alertmanager-main"
},
"value": [
1672995857.892,
"8060"
]
}
]
}
本项目有两种使用方式:第三方库、RESTful服务等
直接在你的项目根路径下执行go get
命令即可。
go get -d github.com/wubin1989/promql2influxql/[email protected]
RESTful服务代码在applications/prom
路径下,是一个单独的go模块。已经有了Dockerfile和docker-compose.yml文件。推荐测试环境采用docker方式部署。
go run cmd/main.go
可看到如下命令行日志输出:
➜ rpc git:(main) ✗ go run cmd/main.go
2023/01/12 19:57:18 maxprocs: Leaving GOMAXPROCS=16: CPU quota undefined
_ _
| | | |
__ _ ___ ______ __| | ___ _ _ __| | ___ _ _
/ _` | / _ \ |______| / _` | / _ \ | | | | / _` | / _ \ | | | |
| (_| || (_) | | (_| || (_) || |_| || (_| || (_) || |_| |
\__, | \___/ \__,_| \___/ \__,_| \__,_| \___/ \__,_|
__/ |
|___/
2023-01-12 19:57:18 INF ================ Registered Routes ================
2023-01-12 19:57:18 INF +---------------------------+--------+----------------------------------+
2023-01-12 19:57:18 INF | NAME | METHOD | PATTERN |
2023-01-12 19:57:18 INF +---------------------------+--------+----------------------------------+
2023-01-12 19:57:18 INF | Query | POST | /api/v1/query |
2023-01-12 19:57:18 INF | GetQuery | GET | /api/v1/query |
2023-01-12 19:57:18 INF | Query_range | POST | /api/v1/query_range |
2023-01-12 19:57:18 INF | GetQuery_range | GET | /api/v1/query_range |
2023-01-12 19:57:18 INF | GetLabel_Label_nameValues | GET | /api/v1/label/:label_name/values |
2023-01-12 19:57:18 INF | GetDoc | GET | /go-doudou/doc |
2023-01-12 19:57:18 INF | GetOpenAPI | GET | /go-doudou/openapi.json |
2023-01-12 19:57:18 INF | Prometheus | GET | /go-doudou/prometheus |
2023-01-12 19:57:18 INF | GetConfig | GET | /go-doudou/config |
2023-01-12 19:57:18 INF | GetStatsvizWs | GET | /go-doudou/statsviz/ws |
2023-01-12 19:57:18 INF | GetStatsviz | GET | /go-doudou/statsviz/* |
2023-01-12 19:57:18 INF | GetDebugPprofCmdline | GET | /debug/pprof/cmdline |
2023-01-12 19:57:18 INF | GetDebugPprofProfile | GET | /debug/pprof/profile |
2023-01-12 19:57:18 INF | GetDebugPprofSymbol | GET | /debug/pprof/symbol |
2023-01-12 19:57:18 INF | GetDebugPprofTrace | GET | /debug/pprof/trace |
2023-01-12 19:57:18 INF | GetDebugPprofIndex | GET | /debug/pprof/* |
2023-01-12 19:57:18 INF +---------------------------+--------+----------------------------------+
2023-01-12 19:57:18 INF ===================================================
2023-01-12 19:57:18 INF Http server is listening at :9090
2023-01-12 19:57:18 INF Http server started in 6.225365ms
在线Swagger接口文档地址:http://localhost:9090/go-doudou/doc
接口文档http basic用户名/密码:admin/admin
打包docker镜像
docker build -t promql2influxql_promql2influxql .
启动RESTful服务和基础设施容器
docker-compose -f docker-compose.yml up -d --remove-orphans
可以看到如下命令行日志输出
➜ rpc git:(main) ✗ docker-compose -f docker-compose.yml up -d --remove-orphans
[+] Running 6/6
⠿ Network rpc_default Created 0.1s
⠿ Container promql2influxql_influxdb Started 1.1s
⠿ Container promql2influxql_node_exporter Started 0.3s
⠿ Container promql2influxql_promql2influxql Started 1.0s
⠿ Container promql2influxql_grafana Started 1.0s
⠿ Container promql2influxql_prometheus Started
以下是各服务的请求地址:
- promql2influxql服务:
http://promql2influxql_promql2influxql:9090
(需要配置到grafana数据源) - promql2influxql服务在线Swagger接口文档地址:http://localhost:9091/go-doudou/doc
接口文档http basic用户名/密码:admin/admin - Grafana:
http://localhost:3000
- Prometheus:
http://localhost:9090
(仅用作监控数据采集服务) - Influxdb:
http://promql2influxql_influxdb:8086
如果需要新增其他数据源的PromQL转译和适配,只需在adaptors/prom
路径下复制一套influxdb
包的代码,修改使用即可。比如需要新增对Elasticsearch数据源的适配,只需将influxdb
包的代码复制一套改成elastic
(或随便什么名字)包,在里面实现转译逻辑,然后在prom
包路径下新增一个elasticadaptor.go
文件,把influxdbadaptor.go
文件里的代码复制进去改改就可以了。
如果需要为Grafana新增其他查询语言的适配服务,需要首先在applications
路径下复制一套prom
包的代码改造成一套适配服务,然后在adaptors
路径下复制一套prom
包的代码改造成适配器,再在适配服务里调用即可。比如需求是用Elasticsearch查询语言去查询InfluxDB里的数据,需要首先在applications
路径下复制一套prom
包的代码,命名为elastic
包,然后在adaptors
路径下复制一套prom
包的代码,命名为elastic
包,在applications
模块下的elastic
包里开发适配服务,在adaptors
模块下的elastic
包里开发适配器,最后在适配服务里调用适配器就可以了。
- Counter:计数器
- Gauge:仪表盘
- Histogram:直方图
- Summary:摘要
- =:相等匹配器
- !=:不相等匹配器
- =~:正则表达式匹配器
- !~:正则表达式相反匹配器
- {}:瞬时向量选择器
- {}[]:区间向量选择器
- [ ] {}[:]:子查询(原生influxql不支持) - offset:偏移量修改器
- by:相当于InfluxQL的group by语句
- [ ] without:忽略指定标签,by的相反操作(原生influxql不支持) - sum:求和
- min:最小值
- max:最大值
- avg:平均值
- stddev:标准差
- [ ] stdvar:标准差异(原生influxql不支持) - count:统计结果行数
- [ ] count_values:按值分组,统计每组的结果行数(原生influxql不支持) - bottomk:样本值最小的k个元素
- topk:样本值最大的k个元素
- quantile:分布统计
- +:加法
- -:减法
- x:乘法
- /:除法
- %:取模
- ^:求幂
- and:且
- or:或
- [ ] unless:排除(原生influxql不支持)
- [ ] ==:等于(原生influxql不支持) - !=:不等于
- >:大于
- <:小于
- >=:大于等于
- <=:小于等于
- [ ] bool:0表示false,1表示true(原生influxql不支持)
- [ ] ignoring:忽略标签(原生influxql不支持)
- [ ] on:与ignoring相反,类似by(原生influxql不支持)
- [ ] group_left:多对一,类似sql的左连接(原生influxql不支持)
- [ ] group_right:一对多,类似sql的右连接(原生influxql不支持)
根据官方文档 https://prometheus.io/docs/prometheus/latest/querying/functions/#trigonometric-functions 整理
- abs()
- [ ] absent()(原生influxql不支持)- [ ] absent_over_time()(原生influxql不支持) - ceil()
- [ ] changes()(原生influxql不支持) - clamp():按最大值、最小值区间范围筛选
- clamp_max():按最大值筛选
- clamp_min():按最小值筛选
- [ ] day_of_month()(原生influxql不支持)
- [ ] day_of_week()(原生influxql不支持)
- [ ] day_of_year()(原生influxql不支持)
- [ ] days_in_month()(原生influxql不支持)
- [ ] delta()(原生influxql不支持) - deriv()
- exp()
- floor()
- [ ] histogram_count()(原生influxql不支持)
- [ ] histogram_sum()(原生influxql不支持)
- [ ] histogram_fraction()(原生influxql不支持)
- [ ] histogram_quantile()(原生influxql不支持) - holt_winters()
- [ ] hour()(原生influxql不支持) - idelta()
- increase()
- irate()
- label_join()
- label_replace()
- ln()
- log2()
- log10()
- [ ] minute()(原生influxql不支持)
- [ ] month()(原生influxql不支持) - predict_linear()
- rate()
- resets()
- round()
- scalar()
- sgn()
- [ ] sort():InfluxDB只支持order by time,Prometheus只支持order by value
- [ ] sort_desc():InfluxDB只支持order by time,Prometheus只支持order by value - sqrt()
- time()
- timestamp()
- vector()
- [ ] year()(原生influxql不支持) - avg_over_time()
- min_over_time()
- max_over_time()
- sum_over_time()
- count_over_time()
- quantile_over_time()
- stddev_over_time()
- [ ] stdvar_over_time()(原生influxql不支持) - last_over_time()
- [ ] present_over_time()(原生influxql不支持) - acos()
- [ ] acosh()(原生influxql不支持) - asin()
- [ ] asinh()(原生influxql不支持) - atan()
- [ ] atanh()(原生influxql不支持) - cos()
- [ ] cosh()(原生influxql不支持) - sin()
- [ ] sinh()(原生influxql不支持) - tan()
- [ ] tanh()(原生influxql不支持)
- [ ] deg()(原生influxql不支持)
- [ ] pi()(原生influxql不支持)
- [ ] rad()(原生influxql不支持)
- 结束时间取值优先级从最高到最低依次是:
End
参数- PromQL查询命令中的
@
表达式 Evaluation
参数- 当前时间
以上的结果会跟PromQL查询命令中的
offset
表达式再计算得出最终的结束时间
- 开始时间只取
Start
参数
因为原生InfluxQL不支持Prometheus的/api/v1/query_range
接口的step
参数和相应的计算机制,例如一段时间范围内,每隔3分钟,计算一次前10分钟的http请求增长速率,原生InfluxQL只能做到利用group by time(3m)
语句实现一段时间范围内每隔3分钟,计算一次前3分钟的http请求增长速率,所以本项目对此的处理方式是:当PromQL查询语句中包含区间向量查询,例如go_gc_duration_seconds_count[5m]
中的[5m]
,同时传了Step
参数,则忽略Step
参数,取区间时间范围的5m
作为group by time(interval)
语句中的interval
参数值。
原生InfluxQL语句实现不了,后续计划通过进行多次InfluxQL查询后在内存中计算实现。
本项目参考了 https://github.com/influxdata/flux 项目的PromQL转Flux转译器的代码。此外,还依赖了很多非常优秀的开源项目。在此向各位开源作者表示感谢!
MIT