一、为啥迁完就炸?先看两个数据库的根本区别
很多公司换Prometheus的核心原因是它的生态太香了——云原生场景下,K8s、Docker、各类中间件都自带Prometheus exporter,而InfluxDB早期在这方面的配套没那么全。但刚迁完的第一周,Grafana面板爆红是常态,问题的根儿不在Grafana,而在InfluxDB和Prometheus的底层数据模型、函数逻辑完全是两码事,像是把安卓APP直接装到iOS上,能不报错吗?
1.1 数据模型的“换壳”差异
咱用大白话讲:InfluxDB的“数据结构”像是带分类标签的快递盒,每个测量点(相当于盒子)里能放好几个不同类型的物品(字段),盒子上还能贴多个标签(比如主机名、环境)区分品类。而Prometheus的结构更像“指标名+标签对”,每个指标只能对应一个数值(相当于盒子里只剩一个核心物品),标签对用来过滤不同维度的时间序列。 举个直观的例子: 原来InfluxDB里的CPU数据大概是这样的:
SELECT * FROM "cpu" WHERE host='server01'
结果会是:cpu=total, usage_idle=50, usage_user=30, time=1690000000000 转成Prometheus后,这个数据就变成两个独立的指标了:
# Prometheus的CPU空闲率指标,带主机标签
cpu_usage_idle{host="server01",cpu="total"} 50
# CPU用户态使用率是另一个独立指标
cpu_usage_user{host="server01",cpu="total"} 30
这个结构差异是最坑的第一步:原来一个测量点能拿多个字段,现在要拆成多个指标名,要是没注意到这个,Grafana里直接就会出现“no data”的报错。
二、最坑的:函数替换的“避坑指南”
光换数据模型还不够,两个数据库的函数逻辑也不一样,比如InfluxDB里的mean(),转Prometheus里不是直接叫mean,而是用avg_over_time(),这还只是入门的,还有更复杂的函数比如rate、quantile、derivative,换错了结果差好几倍,甚至直接报错。
2.1 基础聚合函数的直接替换
先从最常用的聚合函数说起,比如求1小时内每5分钟的平均CPU使用率,对比两个数据库的写法:
InfluxDB原写法
# 求server01主机5分钟粒度的平均空闲CPU,时间范围是最近1小时
SELECT mean("usage_idle") FROM "cpu"
WHERE host='server01' AND time > now()-1h
GROUP BY time(5m)
转成Prometheus的正确写法
# 用avg_over_time求区间内的平均值,[5m]是聚合粒度,[1h]是整体时间范围
avg_over_time(cpu_usage_idle{host="server01"}[5m])[1h]
这里要注意:InfluxDB的GROUP BY time(5m)是把结果按5分钟分桶,每个桶算平均;Prometheus的avg_over_time(cpu[5m])就是完全一样的效果,后面的[1h]是取最近1小时的所有5分钟桶的结果,这样Grafana面板的时间范围设置成最近1小时的话,直接就能出来正常曲线。
2.2 时间处理的“暗坑”
除了聚合函数,时间范围的写法也完全不同:InfluxDB里的time > now()-1h是直接写在查询条件里,而Prometheus的时间范围是用“括号选择器”,刚才例子里的[5m]、[1h]就是,单位不能混(m是分钟、h是小时、s是秒),要是把1h写成1就会出问题,时间长度的单位必须明确。
还有个容易踩的坑:InfluxDB的函数是对“字段”操作,Prometheus的函数是对“时间序列”操作。比如原来InfluxDB里的derivative()(求速率),转Prometheus不是直接用derivative,而是要看指标类型:如果是计数器(比如请求数,一直单调递增),就要用rate()函数;如果是Gauge(比如CPU使用率,上下波动),要用delta()函数,这个一定要分清楚,不然速率算出来是负的或者跳变很大,直接导致面板红掉。
三、具体场景的报错解决示例
咱拿真实的企业监控场景举例:公司要把全服务器的CPU使用率面板从InfluxDB迁到Prometheus,Grafana里原来的全绿面板迁完后全红,一步步改过来的过程:
3.1 示例1:CPU使用率面板的从0到1修改
原InfluxDB面板的查询是:
# 找所有host前缀为server的主机,总CPU的空闲率,最近24小时,每10分钟聚合一次
SELECT mean("usage_idle") FROM "telegraf"."autogen"."cpu"
WHERE host =~ /^server/ AND cpu='cpu-total' AND time > now()-24h
GROUP BY time(10m)
Grafana里的时间范围设置是Last 24h,原来的面板正常,迁完后直接报错“query execution failed”。
改的关键步骤:
- 拆字段转指标:原来的
usage_idle是InfluxDB的字段,现在换成Prometheus的指标cpu_usage_idle; - 过滤条件适配:InfluxDB的
host=~/^server/是正则过滤,转Prometheus里是host=~"^server",语法一致,只是引号用双引号; - 聚合函数替换:
mean()换成avg_over_time,时间聚合粒度保持10分钟; - 时间范围适配:原InfluxDB里的24小时范围转成Prometheus的整体时间范围选择器,指标里加
[10m],Grafana的时间范围设置不用改。
最终的PromQL正确写法:
# 所有server前缀主机的总CPU空闲率,每10分钟平均,最近24小时
avg_over_time(cpu_usage_idle{host=~"^server",cpu="cpu-total"}[10m])[24h]
改完后Grafana面板的红线就消失了,正常曲线出来了。
3.2 示例2:请求速率面板的函数替换
原来的请求数面板,InfluxDB的写法是:
# 求200状态码的请求速率,最近1小时,每10秒算一次
SELECT derivative(sum("value"), 10s) FROM "http_requests"
WHERE status='200' AND time > now()-1h
迁完后报错“no data points”,为啥?因为原来的derivative函数是对字段求差除以时间,而Prometheus里的请求数是计数器类型,单调递增,应该用rate函数自动处理计数器的重置(比如服务重启后请求数清零,rate会自动补全缺失的点),直接算每秒的增长率:
正确的PromQL写法:
# 200状态码的请求速率,每10秒聚合,最近1小时
rate(http_requests{status="200"}[10s])[1h]
这个结果和原来InfluxDB的derivative完全一致,不会出现数据缺失或者跳变的问题。
四、注意事项与常见坑
Prometheus和InfluxDB各有优劣,迁库前要先明确场景:Prometheus的优点是生态极丰富,云原生场景下几乎是标准,Grafana集成不用额外配置,服务发现自动拉取指标,适合分布式系统监控;缺点是数据模型严格,每个指标只能有一个数值,标签不能太多(基数太高会导致性能下降,比如每个主机的每个CPU都带标签,基数会炸),不适合存大量多字段的时序数据(比如IoT的传感器数据)。 InfluxDB的优点是灵活,支持多字段存储,适合海量时序数据,比如IoT场景的多维度数据;缺点是生态不如Prometheus,云原生集成麻烦,Grafana的支持度没那么顺,适合小众或者传统时序存储场景。 迁库的核心注意事项:不要一次性全换,先测小面板,比如改一个CPU面板,没问题再改其他的;函数替换一定要对应指标类型,计数器用rate,Gauge用delta,聚合函数要对应;标签只留必要的维度,不要乱加标签导致基数过高,引发查询失败。
五、总结
从InfluxDB迁到Prometheus,核心是先搞懂两者的数据模型差异,再逐个替换函数,不要怕报错,大部分都是细节问题,比如指标名、函数类型、时间范围的写法。先从小面板验证,再大面积推广,这样就能快速把Grafana的红线全部改成正常的曲线。只要把数据模型和函数替换的坑踩过一遍,下次再迁就稳了,不会再出现大面积报错的问题。
评论
围绕“从InfluxDB迁移到Prometheus后Grafana看板大面积报错,数据模型差异与函数替换指南”参与讨论