容器CPU使用率高于节点CPU使用率的问题排查求助
背景
我正尝试将整个系统(如raspberrypi)的能耗分配给无服务器函数的Pod,但得到了异常结果。已搭建好完整的能耗测量环境,初期在Kubernetes的OpenFaaS上部署了1个名为analyze-sentence的无服务器函数Pod。
使用Prometheus搭配node-exporter和cadvisor获取Kubernetes节点和容器的CPU使用率指标,能耗则通过自定义的exporter提供对应指标。
已尝试方案
提出一个仅考虑CPU使用率的简单公式,包含以下参数:
- 系统总CPU使用率(百分比):使用指标
node_cpu_seconds_total计算 - 系统CPU总核心数:使用指标
machine_cpu_cores - Pod的CPU使用率(使用的核心数):使用指标
container_cpu_usage_seconds_total(该Pod仅含1个容器) - 系统实测能耗(安培秒As):使用自定义指标
powerexporter_power_consumption_ampere_seconds_total(counter类型,数值准确)
计算逻辑
先计算Pod CPU使用率相对于系统总CPU使用率的百分比:
(Pod CPU使用率 / CPU核心数) / 系统CPU使用率结果区间为
[0...1],再将其与实测能耗相乘得到Pod分配的能耗。从Prometheus获取过去1分钟的指标,CPU使用率使用
rate函数计算平均值,对应的PromQL查询语句:- 系统CPU使用率:
100 - (avg by (instance) (rate(node_cpu_seconds_total{job='node-exporter', instance='raspberrypi', mode='idle'}[1m])) * 100) > 0 - 系统CPU核心数:
machine_cpu_cores{node='raspberrypi'} - Pod CPU使用率:
rate(container_cpu_usage_seconds_total{container='analyze-sentence', image!='', container_name!='POD'}[1m]) > 0 - 系统能耗:
idelta(powerexporter_power_consumption_ampere_seconds_total{instance='raspberrypi'}[2m:1m])idelta计算范围查询中最后两个样本的差值,得到过去60秒的能耗。
- 系统CPU使用率:
问题
偶尔会出现Pod的CPU使用率占比高于系统总CPU使用率的异常情况,部分样本结果如下:
2022-07-30 13:36:05,840 - __main__ - INFO >>> CPU Cores Query >>> [Timestamp: 1659180963.405 | Number of Cores: 8] 2022-07-30 13:36:05,938 - __main__ - INFO >>> Node CPU Usage Query >>> [Timestamp: 1659180963.503 | CPU Usage: 15.909242428069987 %] 2022-07-30 13:36:06,029 - __main__ - INFO >>> Container CPU Usage Query >>> [Timestamp: 1659180963.594 | CPU Usage: 1.4602082000000034 Cores 2022-07-30 13:36:06,116 - __main__ - INFO >>> Energy Consumption Query >>> [Timestamp: 1659180963.68 | Energy Consumption: 19.318549297684513 As] 2022-07-30 13:36:06,116 - __main__ - INFO >>> Container CPU Usage (Percentage) relative to the complete node: 18.25260250000004 % 2022-07-30 13:36:06,116 - __main__ - INFO >>> Energy Consumption of analyze-sentence: 22.164084984030715 As
每60秒查询一次Prometheus REST API,多数结果正常,但偶尔出现该异常。无论何时查询,系统平均CPU使用率都应高于Pod的,请问问题出在哪里?是数据错误、查询语句错误还是方案本身有问题?
问题分析与解决建议
1. 系统CPU使用率计算的准确性问题
当前用avg by (instance)取所有核心idle率的平均值,再推导系统使用率的方式存在误差:多核心负载不均衡时(比如单个核心被Pod占满,其余核心空闲),平均idle率会偏高,计算出的系统总使用率会被低估,进而导致Pod占比被高估。
修正方案:改用sum计算所有核心的总idle时间占比,正确的PromQL为:
100 - (sum by (instance) (rate(node_cpu_seconds_total{job='node-exporter', instance='raspberrypi', mode='idle'}[1m])) / sum by (instance) (rate(node_cpu_seconds_total{job='node-exporter', instance='raspberrypi'}[1m])) * 100)
该公式会先计算所有核心的总idle时间占总CPU时间的比例,再得到系统实际使用率,结果更准确。
2. 指标时间窗口对齐问题
虽然样本时间戳接近,但node-exporter和cadvisor的指标采集间隔可能不同(默认分别为15秒、10秒),导致两个rate函数计算的时间窗口内的实际数据覆盖范围不完全一致,出现短暂的统计偏差。
修正方案:给所有rate查询添加offset参数,强制对齐时间窗口,比如:
# 系统CPU使用率 100 - (sum by (instance) (rate(node_cpu_seconds_total{job='node-exporter', instance='raspberrypi', mode='idle'}[1m] offset 1m)) / sum by (instance) (rate(node_cpu_seconds_total{job='node-exporter', instance='raspberrypi'}[1m] offset 1m)) * 100) # Pod CPU使用率 rate(container_cpu_usage_seconds_total{container='analyze-sentence', image!='', container_name!='POD'}[1m] offset 1m) > 0
确保两者计算的是同一个历史时间区间的平均值。
3. 容器CPU使用率的过滤条件问题
当前查询条件container='analyze-sentence', image!='', container_name!='POD'可能匹配到多个容器(比如同名的历史终止容器、或同一Pod的sidecar容器),导致rate计算的是多个容器的CPU使用率总和,出现数值异常。
修正方案:添加更精确的过滤条件,比如指定Pod名称或命名空间:
rate(container_cpu_usage_seconds_total{container='analyze-sentence', image!='', container_name!='POD', pod=~'analyze-sentence-.*', namespace='openfaas-fn'}[1m] offset 1m) > 0
确保仅查询目标Pod的容器指标。
4. 能耗分配逻辑的局限性
当前方案假设能耗与CPU使用率完全线性相关,但实际系统能耗还包含内存、磁盘、网络等组件的消耗,当Pod CPU使用率较高但系统其他组件空闲时,可能出现分配能耗超过系统实际能耗的情况。
优化方案:如果追求更准确的分配,可以结合内存使用率等指标设置权重;若仅考虑CPU,建议先修正上述查询准确性问题后再验证结果。
内容的提问来源于stack exchange,提问作者Manu

