专栏名称: OSC开源社区
OSChina 开源中国 官方微信账号
目录
相关文章推荐
腾讯技术工程  ·  又更新了!你好,微_____ ·  昨天  
程序员小灰  ·  氛围编程来了!现在做应用,就像和AI聊个天 ·  11 小时前  
老刘说NLP  ·  GraphRAG遇上DeepResearch ... ·  昨天  
51好读  ›  专栏  ›  OSC开源社区

“四两拨千斤”——1.2MB数据如何吃掉10GB内存

OSC开源社区  · 公众号  · 程序员  · 2024-11-03 22:30

正文

请到「今天看啥」查看全文


再结合没有产生 core-dump 文件的现象,如果是内存耗尽导致进程被 oom-killer 进程杀死是说得通的。因为oom-killer 进程使用 SIGKILL 信号强制杀死进程,查看 Linux 信号手册,根据 POSIX.1-1990 标准, SIGKILL 信号意味着进程被强制结束并且不进行核心转储。

Signal      Standard   Action   Comment  ────────────────────────────────────────────────────────────────────────  ...  SIGIOT         -        Core    IOT trap. A synonym for SIGABRT  SIGKILL      P1990      Term    Kill signal  SIGLOST        -        Term    File lock lost (unused)  ...
瞌睡遇上枕头,刚好发现监控平台上线了单机秒级监控(感谢平台工具给力),再找到发生 crash 的机器和时间点,发现推测是对的,在几秒内其中一个 worker 进程内存占用飙升,从几百 MB 一路暴涨到十几 GB,在 8C16G 规格的机器上很快就因为内存耗尽被内核杀掉。

问题查到这里,好消息是排查方向总算对了,坏消息是 OOM 进程闪退只是问题的表现,而导致内存飙升的根本原因还是没什么头绪。

怀疑有异常的攻击流量,然而查看闪退前后该机器的网络流量,inbytes 和 outbytes 并没有波动,所以也基本排除了被突发流量攻击;怀疑是网关上 ip geo 信息查询的二分查找逻辑有死循环,经过代码检查和测试也没发现这里有问题;甚至怀疑系统跑久了有内存碎片,但经过排查也排除了这种可能,今年之前也没出现这种问题。

所以目前的情况就是在没有任何外部攻击的情况下,系统内存突然就爆了。这还真是见了鬼,排查了这么多问题,如此诡异的情况也是少见。

core-dump!

core-dump 文件是进程闪退前最后的“遗照”,类似尸检之于法医,对于查问题能提供非常多线索。拿不到转储文件真是两眼一抹黑 —— 全靠猜。所以痛定思痛,决定想办法把 core-dump 文件拿到。

既然闪退是因为内存占用过高,而被 oom-killer 杀死又不会进行核心转储,总不能到 Linux 内核里修改 oom-killer 发送的信号。在跟师兄讨论时,师兄提出一个思路:在用户态实现一个 oom-killer(青春版),当然没有复杂的打分逻辑,只需要检测目标进程的内存用量,到阈值之后发送一个可以产生内核转储行为的信号来杀死进程,通过主动杀死进程的方式产生 core-dump 文件。

后面师兄抽空帮忙写了一个 nginx 辅助进程,逻辑是每秒检测一次所有 worker 进程的内存用量,如果超过一定阈值就发送 SIGABORT 信号主动杀死对应进程。当然为了防止工具误杀导致更严重的问题,限制在应用重启后的生命周期内最多只会触发一次。

找了部分机器部署之后,还真给拿到了 core-dump 文件,不过还有个小插曲,第一次拿到的文件过大发生了截断,后续又将单进程的内存阈值从 8GB 调整为 4GB,终于拿到了完整可用的 core-dump!

如上图可以看到程序的堆栈,这种通过自杀产生的内核堆栈不像内存越界的堆栈直接指向了程序崩溃点,当前的堆栈只能反应程序在异常时执行的代码,不一定是准确的问题点,但也能提供非常多的线索。从堆栈结合代码可以看出程序正在进行数据攒批写出, 再往前是 schema 埋点数据的拆分,攒批写出时恰好在调用 ngx_pcalloc 函数从内存池中申请内存,所以很可能是在 schema 埋点数据拆分之后的攒批发送时内存分配出了问题。







请到「今天看啥」查看全文