温馨提示×

如何利用日志进行Node.js集群监控

小樊
39
2025-12-16 09:27:27
栏目: 编程语言

Node.js 集群日志监控实战指南

一 核心原则与落地要点

  • 使用结构化日志(JSON),统一字段如:timestamp、level、service、instance、pid、hostname、trace_id、msg,便于检索与聚合。
  • 规范日志级别Fatal、Error、Warn、Info、Debug、Trace,生产以 Info/Warn/Error 为主,调试期开启 Debug
  • 集群中为每条日志注入workerId/pid,保证多进程日志可区分与可追踪。
  • 采用集中式日志:如 ELK(Elasticsearch、Logstash、Kibana)Fluentd → Graylog,避免仅在本机查看日志。
  • 做好日志轮转与保留策略,防止磁盘被占满;对高频日志设置采样或降级,降低开销。

二 采集与架构选型

  • 开发/单机快速观测
    • 使用 PM2:进程管理 + 实时日志流(命令:pm2 start app.jspm2 logs),适合本地与预发环境。
    • 使用 Log.io 搭建轻量实时日志服务(安装:npm i -g log.io-server log.io-file-input),便于多人协作排查。
  • 容器与云原生
    • Kubernetes 中优先用 Sidecar 容器收集日志,降低对业务侵入性;日志落盘或 stdout 再由 Sidecar 统一采集。
  • 生产级集中式方案
    • ELK:Node.js 将日志发至 Logstash(如 HTTP 5044Filebeat),入 Elasticsearch,用 Kibana 检索与可视化。
    • Fluentd → Graylog:Node.js 输出 JSON,Fluentd 解析后转为 GELF 推送到 Graylog,便于字段解析与告警。

三 最小落地示例

  • 结构化日志输出(Winston,注入 workerId)
// logger.js
const { createLogger, format, transports } = require('winston');
const { combine, timestamp, json } = format;
const cluster = require('cluster');

const logger = createLogger({
  level: process.env.LOG_LEVEL || 'info',
  format: combine(timestamp(), json()),
  defaultMeta: {
    service: 'order-service',
    instance: process.env.HOSTNAME || 'unknown',
    pid: process.pid,
    workerId: cluster.isWorker ? cluster.worker.id : 'master'
  },
  transports: [
    new transports.Console(),
    new transports.File({ filename: 'logs/error.log', level: 'error' }),
    new transports.File({ filename: 'logs/combined.log' })
  ]
});

// 可选:按天轮转(需安装 winston-daily-rotate-file)
// new transports.DailyRotateFile({ filename: 'logs/app-%DATE%.log', datePattern: 'YYYY-MM-DD', zippedArchive: true })

module.exports = logger;
  • 在业务代码中统一使用
// app.js
const logger = require('./logger');
const cluster = require('cluster');
const express = require('express')();
const app = express();

app.get('/health', (req, res) => {
  logger.info('health check ok', { status: 'UP', ts: Date.now() });
  res.json({ status: 'UP' });
});

app.get('/error', () => {
  logger.error('something went wrong', { path: '/error', code: 500 });
  throw new Error('boom');
});

if (cluster.isMaster) {
  const numCPUs = require('os').cpus().length;
  for (let i = 0; i < numCPUs; i++) cluster.fork();
  cluster.on('exit', (worker) => {
    logger.warn('worker exited', { workerId: worker.id, pid: worker.process.pid });
  });
} else {
  app.listen(3000, () => logger.info('worker started', { port: 3000 }));
}
  • 运行与查看
    • 开发:node app.js
    • PM2:pm2 start app.js -i max && pm2 logs

四 集中式监控与告警配置

  • 方案A:ELK 管道
    • Logstash 配置示例(HTTP 输入 → 解析 JSON → 输出到 ES)
      input {
        http {
          port => 5044
          codec => json
        }
      }
      filter {
        mutate { remove_field => ["@version"] }
      }
      output {
        elasticsearch {
          hosts => ["http://es:9200"]
          index => "nodejs-cluster-%{+YYYY.MM.dd}"
        }
      }
      
    • Kibana 中建立索引模式 nodejs-cluster-*,创建可视化与告警(如:5 分钟内 ERROR ≥ 10 触发告警)。
  • 方案B:Fluentd → Graylog
    • Fluentd 将应用日志(JSON)解析为 GELF 并发送到 Graylog,利用 Graylog 的搜索、仪表盘与告警规则进行监控。

五 关键指标与优化建议

  • 日志字段与健康关联
    • 通过 /health/metrics 输出健康与关键指标,日志中记录 trace_id,实现请求链路串联与根因定位。
  • 性能与成本
    • 选择高性能日志库(如 PinoWinstonBunyan),避免同步写磁盘;对高频调试日志进行采样降级
    • 配置日志轮转与保留策略(如按天归档、压缩与过期清理),防止磁盘被占满。
  • 检索效率
    • 统一 timestamp 时区与格式(ISO8601),为 trace_id、userId、tenantId 等建立索引/可搜索字段,缩短 MTTR。

0