主要学习观察Node.js服务在远程机器上的运行状态,本地运行通过console.log()可以打印大部分信息,但是一但服务器在远程运行,就需要使用别的工具进行观察
环境
环境是用于区分运行的是应用还是数据库实例,是非常重要的,会影响日志的输出、路由的选择、服务的隔离保障安全等
ELK
ELK:三个开源软件的缩写,分别表示:Elasticsearch分布式搜索引擎,可以存储 , Logstash过滤, Kibana可视化。
ELK的基本使用流程如下
使用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
之后会下载一段,看到如下
Mac端的桌面docker也可以看到elk
再然后访问,http://localhost:5601 就可以看到这个页面
一、工具链核心原理与角色分工
- Graphite
- 功能定位:时间序列数据库(TSDB)与可视化工具,包含 Carbon(数据接收服务)和 Whisper(存储引擎),支持层级化指标命名(如
web-api.inbound.response_code.200)。 - 数据格式:基于文本协议,每行包含时间戳、指标名和数值(如
1523610995 web-api.request.count 123)。
- StatsD
- 核心角色:轻量级指标收集代理,通过 UDP 接收数据并聚合后转发至后端(如 Graphite),支持计数器(
count)、计时器(timing)等指标类型。 - 优势:非阻塞 UDP 协议避免阻塞应用线程,适合高频指标上报(如每秒数千次请求)。
- Grafana
- 可视化与查询:通过 Graphite 数据源查询指标,支持灵活的面板配置(如折线图、柱状图)和单位转换(如毫秒、百分比)。
- 动态交互:支持时间范围选择、多指标对比和告警规则设置(如响应时间超阈值触发通知)。
二、Node.js 集成 StatsD 的实践步骤
- 依赖安装与配置
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();
});
- 自定义业务指标
// 跟踪上游服务调用(如 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 配置
- 容器启动命令
# 启动 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(请求状态码分布)
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。
四、性能优化与问题排查
- UDP 丢包处理
- 缓冲与重试:通过
statsd-client配置缓冲池(如bufferFlushInterval: 1000),减少高频发送时的丢包风险。 - 备用协议:在关键业务场景切换为 TCP(需修改 StatsD 配置)。
- 指标命名规范
- 层级结构:使用
.分隔符定义层级(如service.module.metric),便于 Grafana 按维度筛选。 - 业务语义:将业务指标(如
payment.cancelled.count)与系统指标(如cpu.usage)分离。
- Grafana 告警规则
- 配置示例:当
web-api.inbound.response_time.upper_90 > 500ms持续 5 分钟时触发告警,通知渠道支持邮件、Slack 或钉钉。
五、与其他监控方案的对比
| 方案 | 适用场景 | 优势 | 局限性 |
| Graphite + StatsD | 高频指标采集、自定义业务监控 | 轻量级、低延迟、灵活命名空间 | 无原生日志追踪能力,需结合 ELK |
| Prometheus | 云原生环境、多维标签查询 | 内置服务发现、强一致性存储 | 高频数据存储成本高,需额外配置导出器 |
| ELK Stack | 日志分析与全文检索 | 强大的文本搜索与聚合能力 | 时间序列数据处理效率低于 Graphite |
六、总结与扩展方向
通过 Graphite + StatsD + Grafana 的组合,Node.js 应用可以实现从指标采集、存储到可视化的完整监控链路。扩展方向包括:
- 混合架构:集成 Prometheus 补充多维标签查询能力。
- 日志关联:通过 ELK 追踪特定请求的完整链路(如结合 TraceID)。
- 自动化运维:基于 Grafana 告警触发 Kubernetes 自动扩缩容。