分布式Node.js--04观察能力

117 阅读3分钟

主要学习观察Node.js服务在远程机器上的运行状态,本地运行通过console.log()可以打印大部分信息,但是一但服务器在远程运行,就需要使用别的工具进行观察

环境

环境是用于区分运行的是应用还是数据库实例,是非常重要的,会影响日志的输出、路由的选择、服务的隔离保障安全等

ELK

ELK:三个开源软件的缩写,分别表示:Elasticsearch分布式搜索引擎,可以存储 , Logstash过滤, Kibana可视化。 ELK的基本使用流程如下 Pasted image 20231224143759.png 使用ELK需要安装docker
编写一个udp config文件

input {
  udp {
    id => "nodejs_udp_logs"
    port => 7777
    codec => json
  }
}
output {
  elasticsearch {
    hosts => ["localhost:9200"]
    document_type => "nodelog"
    manage_tamplete => false
    index => "nodejs-%{+YYYY.MM.dd}"
  }
}

在msic路径的上一级执行以下命令(不要忘记打开docker)

docker run -p 5601:5601 -p 9200:9200 \
  -p 5044:5044 -p 7777:7777/udp \
  -v $PWD/misc/elk/udp.conf:/etc/logstash/conf.d/99-input-udp.conf \
  -e MAX_MAP_COUNT=262144 \
  -it --name distnode-elk sebp/elk:683

之后会下载一段,看到如下 Pasted image 20240208143402.png Mac端的桌面docker也可以看到elk Pasted image 20240208143520.png 再然后访问,http://localhost:5601 就可以看到这个页面 Pasted image 20240208143721.png

一、工具链核心原理与角色分工

  1. Graphite
  • 功能定位:时间序列数据库(TSDB)与可视化工具,包含 Carbon(数据接收服务)和 Whisper(存储引擎),支持层级化指标命名(如 web-api.inbound.response_code.200)。 
  • 数据格式:基于文本协议,每行包含时间戳、指标名和数值(如 1523610995 web-api.request.count 123)。
  1. StatsD
  • 核心角色:轻量级指标收集代理,通过 UDP 接收数据并聚合后转发至后端(如 Graphite),支持计数器(count)、计时器(timing)等指标类型。 
  • 优势:非阻塞 UDP 协议避免阻塞应用线程,适合高频指标上报(如每秒数千次请求)。
  1. Grafana
  • 可视化与查询:通过 Graphite 数据源查询指标,支持灵活的面板配置(如折线图、柱状图)和单位转换(如毫秒、百分比)。 
  • 动态交互:支持时间范围选择、多指标对比和告警规则设置(如响应时间超阈值触发通知)。

二、Node.js 集成 StatsD 的实践步骤

  1. 依赖安装与配置
npm install statsd-client  # 安装 Node.js 客户端库
const SDC = require('statsd-client');
const statsd = new SDC({ host: 'localhost', port: 8125, prefix: 'web-api' });

2. 中间件集成(以 Fastify 为例)

fastify.addHook('onRequest', (request, reply, done) => {
  statsd.increment('inbound.request.count');  // 计数器:统计请求总数
  const startTime = Date.now();
  reply.header('X-Request-Start', startTime);
  done();
});

fastify.addHook('onResponse', (request, reply, done) => {
  const duration = Date.now() - reply.getHeader('X-Request-Start');
  statsd.timing('inbound.response.time', duration);  // 计时器:记录请求耗时
  statsd.increment(`inbound.response_code.${reply.statusCode}`);  // 按状态码分类统计
  done();
});
  1. 自定义业务指标
// 跟踪上游服务调用(如 recipe-api)
async function callRecipeApi() {
  const start = Date.now();
  try {
    const result = await axios.get('http://recipe-api/recipes/42');
    statsd.increment('outbound.recipe_api.success');  // 成功调用计数
  } catch (err) {
    statsd.increment('outbound.recipe_api.failure');  // 失败调用计数
  } finally {
    statsd.timing('outbound.recipe_api.latency', Date.now() - start);  // 记录延迟
  }
}

三、Docker 化部署与 Grafana 配置

  1. 容器启动命令
# 启动 Graphite + StatsD 容器
docker run -d --name graphite -p 8080:8080 -p 8125:8125/udp graphiteapp/graphite-statsd

# 启动 Grafana 容器
docker run -d --name grafana -p 3000:3000 grafana/grafana

2. Grafana 数据源配置

  • 步骤:登录 Grafana → Add Data Source → 选择 Graphite → 输入 Graphite 服务 IP(非 localhost)和端口(默认 8080)。 
  • 验证:单击 Save & Test,确保返回 Data source is working
  1. 面板设计与查询语法
  • 查询示例 1(请求状态码分布)
aliasByNode(stats_counts.web-api.inbound.response_code.*, 4)  # 按第4层级(状态码)聚合
  • 效果:显示 200 和 500 状态码的请求数量趋势。

  • 查询示例 2(上游服务延迟 TP90)

scale(stats.timers.web-api.outbound.recipe_api.latency.mean_90, 0.001)  # 单位转换为秒
  • 配置:在 Axes 选项卡设置 Y 轴单位为 milliseconds

四、性能优化与问题排查

  1. UDP 丢包处理
  • 缓冲与重试:通过 statsd-client 配置缓冲池(如 bufferFlushInterval: 1000),减少高频发送时的丢包风险。 
  • 备用协议:在关键业务场景切换为 TCP(需修改 StatsD 配置)。
  1. 指标命名规范
  • 层级结构:使用 . 分隔符定义层级(如 service.module.metric),便于 Grafana 按维度筛选。 
  • 业务语义:将业务指标(如 payment.cancelled.count)与系统指标(如 cpu.usage)分离。
  1. Grafana 告警规则
  • 配置示例:当 web-api.inbound.response_time.upper_90 > 500ms 持续 5 分钟时触发告警,通知渠道支持邮件、Slack 或钉钉。

五、与其他监控方案的对比

方案适用场景优势局限性
Graphite + StatsD高频指标采集、自定义业务监控轻量级、低延迟、灵活命名空间无原生日志追踪能力,需结合 ELK
Prometheus云原生环境、多维标签查询内置服务发现、强一致性存储高频数据存储成本高,需额外配置导出器
ELK Stack日志分析与全文检索强大的文本搜索与聚合能力时间序列数据处理效率低于 Graphite

六、总结与扩展方向

通过 Graphite + StatsD + Grafana 的组合,Node.js 应用可以实现从指标采集、存储到可视化的完整监控链路。扩展方向包括: 

  1. 混合架构:集成 Prometheus 补充多维标签查询能力。 
  2. 日志关联:通过 ELK 追踪特定请求的完整链路(如结合 TraceID)。 
  3. 自动化运维:基于 Grafana 告警触发 Kubernetes 自动扩缩容。