【nodejs高可用】前端APM应用监控方案 + 落地

为什么要用APM

在讲所有的内容之前。 举个例子:线上App或者是小程序,点击某个按钮没有响应,做为前端 or 运维人员,需要怎么快速排查 + 定位问题。

常规的排查思路:点击按钮,是否触发js错误->检查接口是否正确返回数据/接口是否报错了。

这种情况下:

有些生产环境上的问题不好排查,比如: (1)运营商问题,用户的运营商劫持了js,导致前端程序报错,或者是CDN某个节点的缓存有问题,导致另外一个老版本的js下线了。

(2)用了第三方的服务,比如支付服务,支付服务超时或者额度达到上限欠费了。

(3)机房故障,导致服务挂掉了,不可用。

APM监控服务的示意图: 实际上就是一个应用监控的东西,可以获取到应用的请求路径等。 会在用户出现异常,或者用户主动上报时,会做收集。

APM的形态

(1)对服务里依赖的硬件性能,比如CPU/内存/硬盘容量进行监控。

(2)性能指标的实时值,出现紧急问题时发生告警。

(3)监测服务的情况,如请求数,响应数,成功率。

(4)错误/ 异常监控,需要agent上报。(这个成本比较高,一般需要应用主动上报)

(5)日志收集,对服务的所有情况进行记录,日志是必不可少的,不管是业务本身,还是访问记录,都尽可能的需要日志,日志会占用较多的硬盘空间,所以需要定期清除日志。清除掉以后的问题就比较难以排查了。

(6)中间件相关的依赖监控,对服务的依赖进行监控,如数据库,缓存,外部服务,几乎所有的响应缓慢问题,都是依赖导致的。

(7)真实场景下,分布式事务追踪,监控发起到完成的情况,通过完整的请求路径,用一个唯一的traceId去标识。

分布式事务的追踪实现的原理:

Trace:一次完整请求的链路。

Span:一次调用过程。

SpanContext:Trace的全局上下文信息,如TraceId。

Profiling - 程序级别的监控分析

一般利于自动化的代码插桩,技术,获取nodejs进程内的方法调用链路。 可以查看调用栈上的总执行时间和每个方法占的百分比。 可以结合V8本身的Profiling,查看可能出现的内存泄漏情况。

NodeJs应用 - 0x火焰图的使用-CPU问题排查

火焰图里,越底层的部分,就是C的实现了,上面的都是js的表现。 对于nodejs来说,上层是js代码,下层是C的代码。 这里,楼主定义了一个a方法和b方法,里面实现了两段垃圾代码,下面上代码。

js 复制代码
const restify = require('restify')
const server = restify.createServer();
function a(){
    for(let i = 0;i<1e8 ;i++){}
}

function b(){
    for(let i =0;i<2e8;i++ ){}
}

server.get('/',(req,res,next)=>{
   a();
   b();
   res.send({});
   next();
})

server.listen(3000,()=>{
    console.log('3000 port runing')
})

process.on('SIGINT',()=>{
    server.close();
})

a方法执行了1e8次,b方法执行了2e8次,针对这种情况,我在引入了0x(火焰图)工具,做了一些Profiling的手段。

js 复制代码
"scripts": {
    "test":"NODE_ENV=production 0x -P 'autocannon -c 20 http://localhost:3000' ./cpu-frame-graph/app.js"
  },

这里我直接yarn test。

他会以20个并发连接访问10s,得到火焰表现图,生产成一个路径存放刚才执行行为的性能分析报告。

上面我们可以清楚的看出来,a方法占用了百分25,b方法占用了百分50,和我们程序的行为一致。

实战中,如果是Nodejs侧的问题,比较容易找的出来,如果是底层涉及到IO事件循环的那块,就比较黑盒了,不太容易能够分析的出来问题。

NodeJs应用 - 0x火焰图的使用-内存的USE指标

首先需要认识一下,NodeJs的USE指标:

Process.memoryUsage可以查看到Nodejs当前进程下占用的内存。

其中:

Rss:操作系统分配给进程总的大小

heapTotal:分配给V8堆的内存大小

heapUse:V8使用的内存大小

external:C系统级库,使用的内存大小 什么情况下会导致OOM? 尤其是在webpack打包的时候,东西比较多,依赖加的比较多的情况下,会导致内存打满的情况。导致CI/CD发布的时候编不过。

nodejs底层V8针对内存使用时有上限的。

64位的操作系统:1.4GB

32位的操作系统:0.7GB

一旦内存的操作使用超过了这个数,就会报错out of memory~

Core和Coredump的问题 内存的结构一圈圈的,被称之为Core。

Coredump:在程序崩溃或者终止的时候,操作系统会把这个行为记录下来打到文件里,这种情况叫做coreDump(内存快照)

排查内存泄漏问题除了查看日志,只能查看Core Dump日志。

NodeJs应用 - 内存监控-内存打满案例

这里推荐全局安装两个工具:

js 复制代码
npm i autocannon -g
npm i clinic -g

autocannon:压测工具

clinic:监控工具

假设我这里有一段程序。

js 复制代码
   function compute() {
        return Buffer.alloc(1e3);
    }

这段程序一直在执行,创建Buffer不做回收。

实现了一个run.sh,脚本内容是:

js 复制代码
set -e

while getopts m:d:f: flag
do
    case "${flag}" in
        m) method=${OPTARG};;
        f) file=${OPTARG};;
        d) duration=${OPTARG};;
    esac
done

clinic doctor --on-port 'autocannon -w 300 -c 100 -d '$duration' localhost:3000/'$method'' -- node $file

这个时候,我使用

./run.sh -f index.js -m cache -d 20

会自动跳出来仪表盘,这个时候可以看到这个应用的监控。

如果Memory那一栏,呈现了一直在增长的情况,说明存在内存泄漏问题。

长期放任不管,达到阈值,会导致应用崩溃!

NodeJs应用 - QPS/TPS/RT-吞吐量指标

QPS:每一秒能执行多少Query,QPS越高,Server可以处理的请求越多。

RT: 响应时间,执行一个请求开始到结束花费了多少时间。

QPS也可以这么计算

QPS = 并发数/平均响应时间,也可以衡量QPS值。

Graphite(石墨)/Grafana - 应用监控,APM采集。

这里推荐两个开源的APM的日志采集工具。

Graphite是处理可视化和指标的开源工具,提供了很多API和插件,目前开源里比较简单易用的工具。强烈推荐!

Graphite架构说明:my.oschina.net/emacs_89248...

会通过采集器->监听器->存储数据库(whisper),用于存储按照时间序列的数据,通常监控类的数据,数据量是非常庞大的。(时序数据库),但是这个UI比较丑。

Grafana是一款用于Go语言开发的数据可视化工具,可以用做数据监控和统计,自带告警能力,界面比上面的好看,定制化能力也很强,笔主公司目前也是用这个。

Grafana + Graphite搭建业务监控平台教程

实际上部署起来比较方便,没有那么复杂。挺傻瓜化的,一些插件自己按需集成下就行了。

这里的操作,我都是用docker操作的。

docker-compose.yml:

js 复制代码
version: "3"
services:
    grafana:
        image: grafana/grafana
        ports:
            - 3000:3000

    graphite-statsd:
        image: graphiteapp/graphite-statsd
        ports:
            - 2003-2004:2003-2004
            - 2023-2024:2023-2024
            - 8125:8125/udp
            - 8126:8126
            - 8080:80

graphite-statsd:用于采集。

grafana:用于做看板大盘分析。

运行直接按照下面这个就行了。

js 复制代码
docker-compose up -d

具体docker以及docker-compose的安装配置过程本文不再过多赘述。

主要是启这两个东西

安装,并且启动起来以后。

直接访问localhost:3000就可以了

grafana默认的账号密码是admin/admin

点击添加,然后把graphite给他关联进去。

配置好之后点Save/Test

程序示例(如何把请求打点):

‌**express-statsd****‌是一个用于Connect**Express**框架的StatsD**路由监控中间件。它能够自动捕获HTTP请求的状态码和响应时间,并将这些数据发送到StatsD服务,以便于监控和性能分析

js 复制代码
const express = require("express");
const app = express();
const expressStatsd = require("express-statsd");

app.use(expressStatsd());

function statsd(path) {
    return function (req, res, next) {
        var method = req.method || "unknown_method";
        req.statsdKey = ["http", method.toLowerCase(), path].join(".");
        next();
    };
}

app.get("/", statsd("root"), (req, res) => {
    if (between(0, 10) > 5) {
        res.status(500).send();
    }
    res.send("Response from a simple GET API");
});

选择一下规则,筛选出我刚才发送的那些请求。

如何把监控上云-alinode

关于Alinode的介绍:www.aliyun.com/product/nod...

里面自带了监控,告警,内存快照,cpu分析,还有大模型给开发者提供一些优化建议,可以说是非常强大!

本身也是开源框架实现的,开发者可以不用过度关心安全隐私问题等。

可以直接把数据上报到阿里云的平台上

使用的时候直接把runtime部署到我们的nodejs应用里,同样官方也支持eggjs等。

部署文档:

help.aliyun.com/zh/nodejs/u...

实际上,上述说的Grafana已经可以满足绝大部分场景了。

后续笔主有机会会继续分享这一块....

相关推荐
恋猫de小郭38 分钟前
Flutter Zero 是什么?它的出现有什么意义?为什么你需要了解下?
android·前端·flutter
牛奔2 小时前
Go 如何避免频繁抢占?
开发语言·后端·golang
想用offer打牌7 小时前
MCP (Model Context Protocol) 技术理解 - 第二篇
后端·aigc·mcp
崔庆才丨静觅7 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60618 小时前
完成前端时间处理的另一块版图
前端·github·web components
KYGALYX8 小时前
服务异步通信
开发语言·后端·微服务·ruby
掘了8 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅8 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅8 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
爬山算法9 小时前
Hibernate(90)如何在故障注入测试中使用Hibernate?
java·后端·hibernate