Prometheus计数器结果异常:Node.js使用prom-client的问题排查
问题分析与修复方案
核心问题点
- 异步函数未同步执行:
batch()是异步函数,但循环中直接调用时未加await,导致函数内逻辑延后执行。此时循环已继续修改c,引发竞态条件——比如c刚到1000时调用batch(),但还没执行计数和重置操作,循环就把c加到1001,导致if(c===1000)判断失效,跳过计数。 - 计数器增量逻辑错误:
counterb.inc({ l1: 'abc' }, c)用当前c值作为增量,若因异步竞态导致c已大于1000才执行该行,会错误累加更大数值,同时重置c=0会丢失中间计数。 - 末尾剩余数据未统计:循环结束时,若
c不足1000,这部分数据不会被counterb统计,直接丢失。
修复后的代码
let c = 0; // 移除async,无异步操作无需异步函数 function batch() { if (c >= 1000) { // 固定增量为1000,避免依赖动态变化的c值 counterb.inc({ l1: 'abc' }, 1000); c = 0; } } async function f() { const readStream = bigtable.createReadStream(...); for await (const row of readStream) { countera.inc({ l1: 'abc', l2: 'bde' }); c++; // 同步调用batch,避免竞态 batch(); } // 处理循环结束后剩余的不足1000行数据 if (c > 0) { counterb.inc({ l1: 'abc' }, c); c = 0; } } f();
补充说明
- 原
batch函数无异步操作,改为同步函数可彻底避免竞态问题。 - 固定批量增量为1000,确保每处理1000行准确计数一次,不再依赖动态变化的
c值。 - 循环结束后必须检查剩余
c值,将最后一批不足1000行的数据补统计到counterb中。 - 你的PromQL查询本身无问题,修复代码计数逻辑后,两者统计结果会保持一致(误差在Prometheus采集精度范围内)。
内容的提问来源于stack exchange,提问作者Akshit Bansal
相关产品推荐
相关产品推荐

