【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已经可以满足绝大部分场景了。

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

相关推荐
Senar24 分钟前
Web端选择本地文件的几种方式
前端·javascript·html
iuyou️25 分钟前
Spring Boot知识点详解
java·spring boot·后端
一弓虽37 分钟前
SpringBoot 学习
java·spring boot·后端·学习
烛阴41 分钟前
UV Coordinates & Uniforms -- OpenGL UV坐标和Uniform变量
前端·webgl
姑苏洛言1 小时前
扫码小程序实现仓库进销存管理中遇到的问题 setStorageSync 存储大小限制错误解决方案
前端·后端
烛阴1 小时前
JavaScript 的 8 大“阴间陷阱”,你绝对踩过!99% 程序员崩溃瞬间
前端·javascript·面试
光而不耀@lgy1 小时前
C++初登门槛
linux·开发语言·网络·c++·后端
方圆想当图灵1 小时前
由 Mybatis 源码畅谈软件设计(七):SQL “染色” 拦截器实战
后端·mybatis·代码规范
lh_12541 小时前
ECharts 地图开发入门
前端·javascript·echarts
jjw_zyfx1 小时前
成熟的前端vue vite websocket,Django后端实现方案包含主动断开websocket连接的实现
前端·vue.js·websocket