Skip to content

[RFC] 快照在内存毛刺时的自动 Dump 机制 #102

@hyj1991

Description

@hyj1991

背景

阅读 一个平均运行一百万次才出现一次的bug,你如何调试这个bug 结合最近的语雀偶发性 Coredump 想到

堆内存的异常不同于 CPU,偶发性的异常请求导致的内存毛刺,也是需要关注的,但是由于是瞬时的内存上涨,不易排查:

  • 本身并非内存泄露,而是异常请求处理逻辑自身需要申请异于正常请求的堆空间
  • 异常请求在插件采集的那一刻已经处理完成,内存恢复正常水位,导致监控无法正常预警
  • 就算恰好采集到异常内存点,监控服务正常给出预警,等开发者收到通知前往控制台时已经无法获得问题快照

另一种和前文类似的场景,异常请求造成了 OOM,正常生成了 Core 文件,存在以下场景导致无法定位

  • 异常请求造成堆内存飙升但是尚未 OOM
  • 正常请求处理申请申请的堆内存成为最后一根稻草,导致 OOM
  • Core 的 Btrace 包含的是最后的正常请求

这种情况下只能通过逆工程 V8 Heap object 来进行进一步问题定位,由于在 core 文件里还原的 Heap object 丢失了 GC root 信息,所以没有办法进行 Dominator tree 的构建,人肉扫除了大字符串类,很难甄别内存泄漏点。

综上 Xprofiler 插件需要提供一个机制,在内存出现毛刺时进行自动 Dump 来辅助这类问题的定位。


具体设计

  • 新增一个 1s 粒度的巡检 Thread
  • 分别构造 int[60 * 60] Ring buffer 存储过去 1min 内的进程 CPU / Heap 大小
  • 每次存储前比较当前 CPU / Heap 大小和历史 1h 内均值,超过阈值则进行自动 Dump
    • 阈值可配置,可动态修改
  • 此功能为可选配置,默认关闭(没有这种场景需求 / 介意额外的性能损耗)
    • 可动态修改开闭状态

存在的副作用

  • 额外的存储开销:60 * 60 * 4 * 2 约 28MB 常驻内存
    • 这里可以通过将 Ring buffer 大小设计为可配置来动态调整
  • 额外的巡检 Thread 的 CPU 开销(可忽略不计)

需要处理的异常场景

  • 一段时间内出现大量毛刺,需要控制只对其中之一进行 dump,防止一次性大量 dump 打垮进程
  • TODO,暂时还没想到

监控服务端的改造

  • 新增主动通知类的告警
  • 增加 xprofiler 配置界面修改下发

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions