You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Express集群中Prometheus AggregatorRegistry聚合指标为空问题求助

Node.js Cluster + Prom-client 跨Worker指标聚合修复方案

问题根源

  1. clusterMetrics()调用位置错误:这个方法只能在Master进程执行,用于拉取所有Worker的指标并聚合。原代码在每个Worker的Express端点中调用,根本无法触发跨进程的指标收集逻辑。
  2. 自定义指标未关联聚合注册表:Worker里的Counter用了默认的register,没有绑定到AggregatorRegistry,导致Master拿不到这些自定义指标。
  3. 默认指标注册逻辑错误:全局调用collectDefaultMetrics时同时传了register和aggregatorRegistry,导致默认指标没正确注册到聚合注册表。
  4. 多Worker的Metrics端点冲突:每个Worker都暴露了/metrics,但只有Master能完成跨进程聚合,Worker的端点完全起不到作用。

修正后的完整代码

const express = require('express');
const cluster = require('cluster');
const os = require('os');
const { 
    AggregatorRegistry, register,
    collectDefaultMetrics, 
    Counter
} = require('prom-client');

const PORT = 3000;

if (cluster.isMaster) {
    // Master进程:管理Worker、暴露Metrics端点
    const aggregatorRegistry = new AggregatorRegistry();
    const masterApp = express();

    // 仅在Master处理Metrics请求
    masterApp.get('/metrics', async (req, res) => {
        try {
            const metrics = await aggregatorRegistry.clusterMetrics();
            res.set('Content-Type', aggregatorRegistry.contentType);
            res.end(metrics);
        } catch (err) {
            console.error('收集指标出错:', err);
            res.status(500).end();
        }
    });

    // Master启动服务监听端口,请求会自动分发给Worker
    masterApp.listen(PORT, () => {
        console.log(`Master进程 ${process.pid} 监听端口 ${PORT}`);
    });

    // 根据CPU核心数创建Worker
    const numCPUs = os.cpus().length;
    for (let i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    cluster.on('online', (worker) => {
        console.log(`Worker ${worker.process.pid} 已启动`);
    });

    cluster.on('exit', (worker, code, signal) => {
        console.log(`Worker ${worker.process.pid} 退出,代码: ${code},信号: ${signal}`);
        cluster.fork(); // 重启Worker
    });
} else {
    // Worker进程:处理业务请求、收集指标
    const workerApp = express();
    const aggregatorRegistry = new AggregatorRegistry();

    // 把默认指标注册到聚合注册表
    collectDefaultMetrics({ register: aggregatorRegistry });

    // 自定义Counter,绑定到聚合注册表
    const counter = new Counter({
        name: "test_counter",
        help: "每个Worker每5秒递增的测试计数器",
        labelNames: ["worker"],
        register: aggregatorRegistry
    });

    // 模拟指标更新
    setInterval(() => {
        counter.labels(process.pid.toString()).inc();
        console.log(`Worker ${process.pid} 计数器已递增`);
    }, 5000);

    // 业务路由
    workerApp.get('/', (req, res) => {
        res.send(`来自Worker ${process.pid} 的问候!`);
    });

    // Worker共享Master的端口,不需要单独指定PORT
    workerApp.listen();
}

关键修改点说明

  • 拆分Master/Worker职责:Master负责端口监听、Worker管理和指标聚合;Worker专注业务逻辑和指标收集。
  • 正确调用clusterMetrics():只在Master的/metrics端点调用这个方法,确保能拉取所有Worker的指标并聚合。
  • 指标绑定聚合注册表:Worker里的默认指标、自定义Counter都明确指定register: aggregatorRegistry,保证Master能收集到这些数据。
  • 避免端口重复监听:Master监听端口后,Worker通过Cluster的端口共享机制接收请求,无需重复调用listen(PORT)。

验证步骤

  1. 启动服务后,访问http://localhost:3000/,会看到不同Worker返回的响应。
  2. 访问http://localhost:3000/metrics,能看到聚合后的test_counter(每个Worker的PID作为标签)和Node.js默认指标。

内容的提问来源于stack exchange,提问作者Tarakeswararao Marla

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 10:39:56