天天看点

「前端」Node.js 服务保姆级监控:带你体验 Prometheus 的魅力

作者:架构思考

一、背景介绍

如果你是一名开发人员或者运维人员,你肯定熟悉在生产中监控和调试应用程序是多么的重要。尤其对于 Node.js 这样的语言来说,更需要强大的监控工具支持。

近两年,我司已有多个 Node.js 服务用于实际业务和项目中,然而,之前的这些项目都比较分散,在运维层面没有进行统一监控,在服务的可用性和稳定性上存在一定的风险,一定程度上也限制了 Node.js 的应用场景。

因此近期我们通过尝试和探索将这些Node.js服务通过开源系统 Prometheus 监控起来,本文将主要介绍如何使用Prometheus 和 Grafana 搭建Node.js服务监控系统,实现实时性能监控,并显示可视化图形。

Prometheus 是一种用于监控和警报的开源系统,可用于对数据中心和云环境中的生产服务进行监控和警告。它可用于服务发现、时间序列数据存储、实时查询和警报聚合,因此是一个强大的工具集合。 使用Prometheus 可以快速和有效地收集它提供的标准指标,轻松实现实时性能监控及报警机制的设置。

Prometheus 的 Node.js 服务监控支持多种使用场景,包括:性能监控,日志文件监控,内存分析以及运行时追踪。使用 Prometheus,可以轻松跟踪 Node.j s服务的URL访问、HTTP头和客户端请求信息,也可以针对每个实例查看服务指标,并将其写入 Prometheus 缓存。

Grafana 是一个数据可视化工具,它可以使用 Prometheus 的指标数据,并可视化出来,用于 Node.js 服务的监控,下图则是使用 Grafana 搭建的一个监控大盘。

「前端」Node.js 服务保姆级监控:带你体验 Prometheus 的魅力

二、环境搭建

温馨提示:此搭建步骤仅供本地开发或测试环境搭建参考,由于生产环境需考虑集群部署等高可用使用场景,故不建议直接用于生产环境。

2.1 准备环境

  1. 安装 Docker (建议使用最新版的 Docker)
  2. 下载 Prometheus 和 Grafana 的 Docker 镜像
docker pull prom/prometheus
docker pull grafana/grafana           

2.2 安装并启动

  1. 使用docker run -d --name=prometheus -p 9090:9090 prom/prometheus 命令使用Prometheus镜像开启Prometheus服务
  2. 使用docker run -d --name=grafana -p 3000:3000 grafana/grafana 命令使用Grafana镜像开启Grafana服务

2.3 连接对应服务

  1. 浏览器输入http://127.0.0.1:9090 进入Prometheus首页
  2. 浏览器输入http://127.0.0.1:3000 进入Grafana首页
  3. 进入Grafana首页,使用管理员账号登录,进入左下角Configuration设置,如图所示
  4. 点击Data Sources,选中Prometheus数据源,点击Add new data source,配置如图所示:
  5. 填写URL为http://prometheus:9090,依次点击保存和测试,完成Prometheus与Grafana的连接 。

2.4 初始化一个Node.js项目

我们先初始化一个 Node.js 项目,做为客户端用于提供采集数据,我们这里以 Nestjs 框架为例,其他框架可自行查看官方文档:

  1. 确保你的操作系统上安装 node.js,并且版本>=10.13.0,然后需要在本机上安装Nestjs脚手架并使用脚手架初始化项目:
$ npm install -g @nestjs/cli
$ nest new nestjs-app           
  1. Nestjs项目接入Prometheus,可使用社区方案快速接入:willsoto/nestjs-prometheus,接入步骤如下:
$ pnpm install @willsoto/nestjs-prometheus prom-client           
  1. 在AppModule中导入PrometheusModule,使用默认配置即可:
import { Module } from "@nestjs/common";
import { PrometheusModule } from "@willsoto/nestjs-prometheus";

@Module({
  imports: [
    PrometheusModule.register()
  ],
})
export class AppModule {}           
  1. 执行命令行pnpm run start启动项目后访问地址http://localhost:[port]/metrics,可查看当前项目默认的监控指标(如下图所示),默认指标可参考文档:default-metrics:
「前端」Node.js 服务保姆级监控:带你体验 Prometheus 的魅力

三、Prometheus指标简介

从上方的指标接口中,我们截取其中一段做介绍:

# HELP nodejs_heap_space_size_used_bytes Process heap space size used from Node.js in bytes.
# TYPE nodejs_heap_space_size_used_bytes gauge
nodejs_heap_space_size_used_bytes{space="read_only"} 170944
nodejs_heap_space_size_used_bytes{space="old"} 43376456
nodejs_heap_space_size_used_bytes{space="code"} 1996896
nodejs_heap_space_size_used_bytes{space="map"} 1510272
nodejs_heap_space_size_used_bytes{space="large_object"} 3676104
nodejs_heap_space_size_used_bytes{space="code_large_object"} 0
nodejs_heap_space_size_used_bytes{space="new_large_object"} 0
nodejs_heap_space_size_used_bytes{space="new"} 596344           

#HELP是一个指标的描述文案,可以解释这个指标的功能 #TYPE是一个指标的类型描述,前面的代表这个指标的名称nodejs_heap_space_size_used_bytes空格后边的代表这个指标的类型,gauge 不带#的就是指标的真实值,它的形式是指标名+值。{}中的内容代表了这个指标的label,也就是这个指标还可以再分属性,比如这个指标是 nodejs 堆内存的大小,里边还可以根据 space 属性分成read_only, old等等。 所有的指标都是这种形式。

四、指标类型

Prometheus中有四种指标类型,Counter(计数器)、Gauge(仪表盘)、Histogram(直方图)、Summary(摘要)。

4.1 Counter

Counter 是只增不减的指标, 一般在定义Counter类型指标的名称时推荐使用_total作为后缀。 比如默认指标中的:

process_cpu_user_seconds_total
process_cpu_system_seconds_total
process_cpu_seconds_total           

统计的就是cpu在该node服务上花费的cpu时间,它是一个累积增长的指标。 如果我们想要统计CPU的使用率 就可以通过1分钟之内CPU的增长时间差除以1分钟得到。 再比如如果我们统计请求的QPS也是同样的道理。

4.2 Gauge

Gauge 是可增可减的指标,侧重于反应指标的实时状态,比如默认指标中的

nodejs_heap_size_total_bytes 81444864
nodejs_heap_size_used_bytes 79206776           

统计的就是node中推内存的大小,它显然不是一直增长的是可增可减的指标。

4.3 Histogram

Histogram 是直方图的意思,它不是单纯一个值的指标,是一个复合的指标,可以统计一个值在各种区间之间的分布情况。看demo如下:

const h = new Histogram({
  name: 'test_histogram',
  help: 'Example of a histogram',
  labelNames: ['code'],
  buckets: [0.1, 0.2, 0.3, 0.4, 0.5, 1],
});

h.labels('200').observe(0.4);
h.labels('200').observe(0.6);
h.observe({ code: '200' }, 0.4);

register.metrics().then(str => console.log(str));           

指标上报结果:

# HELP test_histogram Example of a histogram
# TYPE test_histogram histogram
test_histogram_bucket{le="0.1",code="200"} 0
test_histogram_bucket{le="0.2",code="200"} 0
test_histogram_bucket{le="0.3",code="200"} 0
test_histogram_bucket{le="0.4",code="200"} 2
test_histogram_bucket{le="0.5",code="200"} 2
test_histogram_bucket{le="1",code="200"} 3
test_histogram_bucket{le="+Inf",code="200"} 3
test_histogram_sum{code="200"} 1.4
test_histogram_count{code="200"} 3           

可以看到拿到的结果中有总的次数test_histogram_count 有总的值test_histogram_sum, 有设置的几个区间的值,显示的值是小于该区间值的数量,例如test_histogram_bucket{le="0.5",code="200"} 2表示值小于0.5的有2个,那么也就能计算出0.5-1的个数是 3-2=1。

看一个默认指标中的垃圾回收的指标利用的是histogram

# TYPE nodejs_gc_duration_seconds histogram
nodejs_gc_duration_seconds_bucket{le="0.001",kind="major"} 0 
nodejs_gc_duration_seconds_bucket{le="0.01",kind="major"} 2 
nodejs_gc_duration_seconds_bucket{le="0.1",kind="major"} 2 
nodejs_gc_duration_seconds_bucket{le="1",kind="major"} 2 
nodejs_gc_duration_seconds_bucket{le="2",kind="major"} 2 
nodejs_gc_duration_seconds_bucket{le="5",kind="major"} 2 
nodejs_gc_duration_seconds_bucket{le="+Inf",kind="major"} 2 
nodejs_gc_duration_seconds_sum{kind="major"} 0.008220480993390084 
nodejs_gc_duration_seconds_count{kind="major"} 2           

4.4 Summary

汇总指标,它和 Histogram 比较相似,也是复合指标,但是用的场景不多,默认的指标中没有使用Summary的,可能是因为它不支持聚合操作,只能统计单实例的指标。看例子:

const h = new Summary({
  name: 'test_summary',
  help: 'Example of a summary',
  labelNames: ['code'],
  percentiles: [0.1, 0.3, 0.4, 0.5, 1],
});
h.labels('200').observe(0.2);
h.labels('200').observe(0.4);

h.labels('200').observe(0.5);
h.labels('200').observe(1);

register.metrics().then(str => console.log(str));           

指标上报结果:

# HELP test_summary Example of a summary
# TYPE test_summary summary
test_summary{quantile="0.1",code="200"} 0.2
test_summary{quantile="0.3",code="200"} 0.33999999999999997
test_summary{quantile="0.4",code="200"} 0.41000000000000003
test_summary{quantile="0.5",code="200"} 0.45
test_summary{quantile="1",code="200"} 1
test_summary_sum{code="200"} 2.1
test_summary_count{code="200"} 4           

可以看到它也是统计了总数和总的和,但是和histogram的区别是它统计的是百分比的分布情况,比如quantile="0.4"表示的是40%的值小于0.41000000000000003所以它是在客户端经过计算的,不是简单的增加,这种计算就不能够实现多个实例的聚合。而histogram的区间是可以多实例聚合的。

五、项目接入使用

一旦Prometheus安装并配置完毕,下一步将会是启动 Prometheus 服务,将其连接到需要监控的应用程序和设备。

5.1 Nestjs项目接入

参考上方接入

5.2 其他nodejs项目接入

Node.js本身也可以作为一个数据源供 Prometheus 使用,但是如果想要获得特定应用程序的数据,则需要额外的Prometheus exporter 工具。

在这里,我们直接使用「prom-client」npm包来将Node.js应用程序作为数据源并添加到Prometheus的目标列表中。

步骤1:安装 prom-client 包

以express项目为例,打开你的项目的根目录,然后使用 npm install --savedev prom-client 命令来安装 prom-client npm 包。

步骤2:导出prom-client在APP中定义的metrics

要开始收集指标,请前往应用程序中 app.js 文件 ,在文件最底部添加以下内容:

const client = require('prom-client');    
// Counter
const httpRequestsTotal = new client.Counter({
  name: 'http_requests_total',
  help: 'Total number of HTTP requests made'
});
module.exports = { httpRequestsTotal };   // Export all the metrics           

在应用程序中的每次请求都会生成指标,这些指标可以通过 javaScript 代码来累加,以追踪不同指标的数量。

步骤3:暴露HTTP端口和 endpoint

下一步就是暴露一个HTTP端口(port),以便 prometheus 能够连接到 Node.js 应用,并采集指标数据。在之前定义的 app.js 文件中,添加如下代码来暴露 HTTP 端口:

const express = require('express')
const app = express()

  ...

  // Expose a HTTP port that can be used for Prometheus
  app.get('/metrics', (req, res) => {
    res.status(200).set('Content-Type', client.register.contentType).send(client.register.metrics());
  });

...

// Start application
app.listen(3000)
console.log("The App is running on port 3000")           

这样,你的应用程序就开始监控并服务暴露端口,Prometheus 就可以开始采集Node.js项目的指标数据了。

六、PromQL使用

Prometheus Query Language(PromQL)是一个用于查询和分析时间序列数据的表达式语言。在Prometheus中,您可以使用PromQL来执行以下操作:

  • 查询和聚合指定的度量标准(metrics)
  • 过滤和处理时间序列数据
  • 可视化和警报这些度量标准

以下是一些常见的PromQL查询:

6.1 基础查询

要检索某个度量标准的值,可以使用以下查询:

# 检索 http_requests_total 的值
http_requests_total           

6.2 聚合数据

PromQL支持一些内置聚合函数,例如sum、avg、min、max等。要计算特定度量标准的总和,请使用以下查询:

# 计算 http_requests_total 总和
sum(http_requests_total)           

6.3 过滤时间序列

您可以使用过滤器选择您想要的指标。例如,要选择名称包含“api-server”的指标,请使用以下查询:

# 提取 job 标记的值
http_requests_total{job="api-server"}           

6.4 连接多个样本集

您可以使用运算符将多个样本集组合成单个查询结果。例如,要计算总请求数,请使用以下查询:

sum(http_requests_total{url="/api/*",direction="inbound"}) + sum(http_requests_total{url="/api/*",direction="outbound"})           

以上只是PromQL的基础知识,可参考官方文档查看更多语法和使用示例~

七、Grafana监控面板配置

前面章节我们掌握了PromQL的相关知识,就可以使用Grafana将PromQL查询结果展示为漂亮的图表,Grafana提供易于理解的可视化界面。

点击左侧导航栏的“+”按钮,选择“Dashboard”,然后选择“添加查询”来定义要展示的图表类型。通过Query函数编写PromQL查询语句,返回所需的数据。Grafana还有许多其他的过滤器和操作符,具体可以查阅官方文档。

随着您的数据集增长,您可以在面板中添加更多的图表和信息,并利用Grafana强大的展示和告警功能来跟踪和诊断您的应用程序和基础架构。

步骤1:配置数据源

首先,您需要将Grafana连接到您的数据源。在Grafana中,单击左侧导航菜单上的“数据源”按钮,并添加适当的数据源。

步骤2:创建仪表板

接下来,您需要创建一个新的Grafana仪表板。单击左侧导航菜单上的“仪表板”按钮,然后单击“新建仪表板”。

步骤3:添加仪表盘面板

现在,您可以向仪表板添加一个或多个面板。单击“添加面板”按钮以添加面板。您可以选择不同类型的面板,例如图表、表格等。

对于每个面板,您需要指定查询,并设置显示选项。例如,如果您要监视服务器的CPU使用率,则可以使用PromQL,并选择“折线图”作为显示类型。查询示例如下:

# CPU 使用率
100 - (avg by(instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) 
           

步骤4:调整布局和样式

您可以自定义仪表板的外观和感觉,包括颜色、字体、布局等。您可以使用“面板设置”菜单调整每个面板的高度、宽度、标题、背景色等。

您还可以使用Grafana提供的插件扩展仪表板的功能和样式。

步骤5:保存仪表板

最后,确保保存您的仪表板以便日后查看。在仪表板编辑页面的顶部,单击“保存仪表板”按钮,或使用键盘快捷键“Ctrl+S”。

「前端」Node.js 服务保姆级监控:带你体验 Prometheus 的魅力

八、Grafana告警

Grafana提供了告警规则设定,当监控指标超过或者低于预定的阈值时,系统会自动触发告警通知管理员。下方是Grafana告警配置简单教程:

步骤1:创建告警通道(报警方式)

在告警规则之前,需要先配置告警通道,它是定义如何通知值班、运维人员的方法。Grafana支持很多种通知方法,包括电子邮件、Slack、Webhook等。我们以电子邮件为例:

  1. 进入Grafana界面,点击左侧面板中的“Alerting”选项卡;
  2. 点击“Notification Channels”,选择“New Channel”;
  3. 选择“Email”作为媒介,填写SMTP服务器地址、端口号、账号密码等信息,并测试是否能发送成功。
  4. 也可以选择“DingDing”通知方式,在钉钉群组中添加自定义的机器人(Webhook),然后将机器人的Webhook地址复制到Grafana中,可以使用“Test”按钮车上能否发送成功。BTW,经测试Grafana暂不支持机器人加签的安全设置,可以使用关键词或者IP地址的方式。
「前端」Node.js 服务保姆级监控:带你体验 Prometheus 的魅力

步骤2:创建告警规则

接下来,开始配置告警的规则:

  1. 在左侧面板中的“Dashboard Settings”下,选择“Alerts”选项卡;
  2. 点击“New alerts rule”按钮,弹出页面;

以下是一个示例告警规则,当CPU使用率超过80%时触发告警,并发送钉钉告警通知:

「前端」Node.js 服务保姆级监控:带你体验 Prometheus 的魅力
  • 指标:选择要监控的数据指标
  • 聚合方法:选择对指标聚合的方式,如平均值,最大值,最小值等。
  • 条件:定义告警条件。例如,CPU使用率超过80%,或磁盘空间不足10GB / 20%
  • 客户端间隔:检查指标/条件之间的客户端时间间隔
  • 持续时间:定义连续 X 秒或分钟都达到条件时才触发告警
  • 响应策略:定义了复杂或多条件告警规则后,需要借助停顿窗口来避免不必要的告警

步骤3:绑定通道和规则

最后一步是将告警规则与告警通道进行绑定。只有当告警规则和告警通道都被启用时,告警才能够起作用。

  1. 在告警规则编辑页面,点击 "Notifications" 选项卡;
  2. 关联刚才创建好的邮件通知渠道并且设置邮件主题、文本信息;
  3. 保存规则并返回 Dashboard 查看你配置的告警效果。

总结

本文档演示了如何配置基于 Prometheus 的 Node.js 服务的服务监控,介绍了 Prometheus、Grafana 的功能和Docker 方式安装、Prometheus 中的四种指标、项目接入使用和自定义指标,最后还讲解了常用的 PromQL 语法和 Grafana 监控告警相关的配置方法。 虽然此文章涵盖了一些基础知识,但这里所提供的指导和示例可供任何想要开始使用 Prometheus 和 Grafana 监控服务分析的初学者参考。希望这篇文章能让你和你的团队更好地了解和使用 Prometheus 和 Grafana 来监测和优化 Node.js 服务。

文章来源:叫叫技术团队_https://juejin.cn/post/7231727002461683773