性能监控体系 Easy-Monitor 的架构实现笔记

152 阅读3分钟

背景

在上一篇文章中提到了如何部署企业级Node.js应用性能监控(Easy-Monitor篇)之后,偶然之间在极客时间里看到了作者分享的一个视频,详细介绍了下该项目的架构设计和实现,讲的特别好,爱不释手,我就在这里做一个笔记,方便之后再遇到类似项目设计时翻阅参考。

痛点

线上故障处理,故障定位一体化

  • 采集 Status、CPU、Memory、Pid
  • 采集 Heap Statistics、Heap Space、Active Handles、Active Requests
  • 更多内核数据
    • 应用的 GC 状态是否健康
    • Libuv 的每一个活跃的句柄详情,类似于 setTimeout
    • 再任意状况下都能对进城进行采样/导出快照

理想的性能监控方案

  • 内核数据:基本采集展示
  • 运维告警:异常感知机制
  • 实时诊断:故障排查能力

解法

Node.js Addon: 用于扩展 Node.js 的功能机制,允许开发者使用 C/C++ 编写本机模块,特别适合用于需要大量计算、访问底层系统资源或与其他 C/C++ 代码集成的场景

监控插件(Addon)

image.png 根据配置添加致命错误钩子:在线程 Crash 时可以输出日志。 根据配置 Monkey Patch:Patch HTTP 模块,用于记录请求的响应时间。

内核数据采集线程:

image.png 接收采样指令线程: image.png 堆快照和 Heap 采样区别? 如果在采样时仍然存在内存泄露,则使用 Heap 采样可以方便找出问题,否则需要使用堆快照来处理。

为什么采用 IPC Server 而不是 TCP Service? TCP Service 是跨终端通信,需要占用端口。 image.png

为什么采用 RequestInterrupt/uv_async_send? 无论 JS 工作线程处于什么状态,比如卡死了或者不能再工作了,都能执行 Profiling 动作。 image.png

为什么不选择直接基于 Node.js Runtime 去改,类似于 Alinode? 功能更加强大,但维护成本高,每次 Node.js 升级都需要修改原有代码。

image.png 插件模块是直接上报好还是采集/控制分离好? 采集/控制分离更好,稳定性更高,采集服务挂了,但业务线程不受影响,也不会出现和业务无关的异常日志

image.png

监控服务端架构

image.png 为什么要把日志处理与存储服务和 Agent 长连接服务分开? 在线上实例非常多,比如 10 万级别,如果没有分开,一旦日志处理与存储服务功能迭代,重新部署时会导致长连接重连,进一步会导致日志服务端雪崩效益,哪怕可以通过随机连接来减少影响,但仍然会降低日志服务的稳定和可用性。而通过将其分离,并且把 Agent 长连接服务逻辑尽可能轻,则可以规避该影响。

用户控制台

image.png 鉴权模块和团队协作

image.png 告警规则

image.png

image.png 可视化

image.png 完整的应用故障定位步骤

image.png 优势

  • 用户简单易用
    • 仅需在 Node.js 应用入口引入插件模块
    • 低侵入性,无需更改现有业务代码
  • 监控功能完备
    • 针对Node.js 应用指标的性能监控
    • 灵活可配置的自定义运维阈值告警
    • 可实时导出的 Runtime 采样与快照

使用案例

内存泄露

使用堆快照,找到 Retained Size 最大的地方,Retainders 可以看到父引用持有点是谁。

进程卡死

CPU 打满,使用诊断报告(也可以用 CPU Profile)打出实时 JS 堆栈。

参考