如何排查并解决AWS EC2 t2.small实例内存使用率飙升问题?

如何排查并解决AWS EC2 t2.small实例内存使用率飙升问题?

我在管理AWS EC2 t2.small实例的项目时,遇到了一个相当棘手的问题:内存使用率不断上升,最终飙升到 90% 以上,导致 Web 应用性能下降。为了缓解问题,我们暂时设置了定时任务,每小时重启一次实例。虽然这是权宜之计,但远非根本解决方案。本文记录了我一步一步排查内存泄漏和优化内存使用的过程,希望对遇到类似问题的运维或开发同仁有所帮助。

一、环境说明与初步观察

EC2 实例信息:

  • 实例类型:t2.small
  • 内存:2GB
  • 系统:Amazon Linux 2(基于 CentOS)
  • 应用架构:Nginx + Node.js Web 应用 + MongoDB(远程)

问题描述:

  • 内存使用率从启动时的 30% 缓慢上升至 90%+
  • 负载并不高,请求量稳定
  • 没有明显错误日志或崩溃,但性能逐渐下降
  • 每小时重启实例可以临时缓解内存问题

二、排查思路总览

内存持续上升且无明显释放迹象,常见原因包括:

  • Web 应用存在内存泄漏;
  • 某些后台服务未正确释放资源;
  • 使用了缓存机制但未设上限;
  • 存在僵尸进程或守护进程泄漏;
  • 操作系统层面调度问题。

三、排查步骤与实战操作

1. 使用 top 或 htop 实时查看内存占用情况

top -o %MEM

重点关注哪些进程常驻内存、内存占用是否持续增长。我观察到 node 进程在长时间运行后,RSS(常驻内存)持续增长。

2. 启用 ps 和 smem 精细分析进程内存

sudo yum install smem -y
smem -r -k | sort -nr -k 4 | head -10

这个命令可以帮助我看到各进程的 Proportional Set Size (PSS),更真实地反映共享内存带来的影响。

3. 检查 Node.js 应用的内存使用(可能的内存泄漏)

a. 查看 Node.js 内存使用限制:

node --v8-options | grep memory

默认 Node.js 只分配约 512MB 堆内存。我怀疑应用未释放对象或缓存导致堆内存增长。

b. 引入内存快照工具

安装 heapdump:

npm install heapdump --save

在应用中添加:

if (process.env.NODE_ENV === 'production') {
  const heapdump = require('heapdump');
  setInterval(() => {
    const filename = `/tmp/heapdump-${Date.now()}.heapsnapshot`;
    heapdump.writeSnapshot(filename, (err, filename) => {
      if (!err) console.log('Heap dump written to', filename);
    });
  }, 1800000); // 每半小时 dump 一次
}

然后下载 .heapsnapshot 文件,使用 Chrome DevTools → Memory 工具分析对象增长情况。最终我发现某个缓存服务(自定义对象池)未设置清理逻辑,导致大量对象长期驻留内存。

4. 检查是否存在日志写入泄漏或文件句柄泄漏

lsof -p <PID> | wc -l

某次排查中我发现 node 子进程保持了大量未关闭的文件描述符,是日志模块未正确关闭流的问题。

5. 检查系统级缓存与 swap

a. 查看缓存和 swap:

free -m

输出示例:

              total        used        free      shared  buff/cache   available
Mem:           2048        1800          80          20         168         120
Swap:           512         300         212

如果 buff/cache 持续上升,可能是系统层面的缓存压力,可手动清理测试:

sudo sync; sudo sysctl -w vm.drop_caches=3

注意:仅用于临时测试,不建议频繁使用。

6. 启用 CloudWatch Memory Metrics(自定义)

默认 EC2 不显示内存使用图表,我通过如下方式开启:

a. 安装 CloudWatch Agent:

sudo yum install amazon-cloudwatch-agent

b. 配置内存监控:

编辑配置文件 /opt/aws/amazon-cloudwatch-agent/bin/config.json 添加:

{
  "metrics": {
    "metrics_collected": {
      "mem": {
        "measurement": [
          "mem_used_percent"
        ],
        "metrics_collection_interval": 60
      }
    }
  }
}

然后启用并查看 CloudWatch 图表以定位内存增长周期。

四、最终解决方案

经过上述多维度排查,我确认问题为:

  • Node.js 应用某个缓存组件在请求后未正确释放对象;
  • 默认 V8 垃圾回收机制在低内存实例上表现不佳;
  • 系统未启用内存使用限制与预警机制。

我做了如下处理:

  • 优化代码,清理不再使用的引用;
  • 设置缓存对象 TTL;
  • 将 Node.js 启动参数加入堆限制:
node --max-old-space-size=384 app.js

使用 PM2 管理进程,并配置内存超限自动重启:

pm2 start app.js --max-memory-restart 400M

升级实例类型为 t3.medium(2 vCPU / 4GB 内存),避免资源瓶颈。

内存占用问题往往不是一次重启能解决的,它反映的是系统资源与应用设计之间的矛盾。通过本次排查,我深刻体会到工具监控 + 代码优化 + 系统调度三者结合的重要性。如果你也遇到类似问题,不妨试试上述方法,或进一步使用如 valgrind、strace 等工具深入排查底层问题。

未经允许不得转载:A5数据 » 如何排查并解决AWS EC2 t2.small实例内存使用率飙升问题?

相关文章

contact