一、问题现象与初步感知

1.1 什么是RSS

很多人第一次接触服务器内存的时候,会看到ps命令里的RSS字段,其实简单说就是“程序在物理内存里占的实打实的空间大小”,就像你把电脑里的一个软件打开,它在内存里的真实占用量,不是虚拟内存那种虚拟的数字,是实打实占了多少物理内存。比如你打开微信,任务管理器里的“内存”就是类似RSS的概念,Nginx-RTMP进程的RSS持续增长,就是它占的物理内存越来越多,久了就会把服务器的物理内存占满,导致其他服务用不了,甚至服务器卡死。

1.2 问题的初步发现

通常这种问题都是在凌晨的时候被发现的,因为运维白天要做别的事,晚上服务器的流量可能稳定,或者有人值班的时候监控告警响了。比如你设置了服务器内存告警,阈值设的是70%,凌晨3点多告警响了,你登上去一看,Nginx-RTMP的RSS从一周前的500MB涨到了8GB,而且重启Nginx之后,RSS又回到500MB,过两天又涨回来,这就是典型的内存泄漏现象,就像你手机上开了个直播APP,不用了也不关掉,慢慢占满内存,最后手机卡到不动。

二、排查前的准备工作

2.1 必备排查工具的简单说明

排查这种问题不用装复杂的工具,服务器自带的几个命令就够了,都是“轻量级选手”:

  • ps:服务器的任务管理器,能看每个进程的内存、状态这些,就像手机的任务管理器;
  • curl:用来调Nginx-RTMP的状态接口,看连接数、流的情况,就像你在浏览器里打开一个网页;
  • grep、awk:用来过滤和提取需要的数据,就像你在一堆文字里找你要的内容;
  • date:看当前时间,方便对比不同时间的内存数据,就像你记日记的时间戳。 这些工具都是Linux服务器自带的,不用额外装,只要你能登服务器,有执行命令的权限,就能用。

2.2 进程与内存数据的采集示例

这里给一个完整的bash脚本,用来定时采集Nginx-RTMP的RSS和RTMP连接数,方便你观察内存的变化规律,比如是稳定涨还是突然涨,连接数和内存变化有没有关联,脚本的注释都写得很清楚,你直接复制到服务器上就能用:

#!/bin/bash
# 这个脚本用于定时监控Nginx-RTMP进程的RSS占用和活跃连接数
# 第一步:找到Nginx主进程的PID,因为主进程会管理所有工作进程
# ps -ef 是看所有进程,grep nginx过滤出nginx进程,grep master过滤主进程,awk提取PID
NGINX_PID=$(ps -ef | grep -E 'nginx: master process' | grep -v grep | awk '{print $2}')
# 检查是否找到Nginx进程,如果没找到就提示退出
if [ -z "$NGINX_PID" ]; then
    echo "错误:没有找到运行中的Nginx进程,请检查服务是否启动"
    exit 1
fi
# 循环采集30次,每次间隔1秒,你可以根据需要修改次数和间隔
for ((i=1; i<=30; i++)); do
    # 从ps输出中提取RSS,ps的RSS单位是KB,所以除以1024转成MB,方便看
    RSS_MB=$(ps -p $NGINX_PID -o rss= | awk '{print int($1 / 1024)}')
    # 调用Nginx-RTMP的状态接口,获取活跃连接数,接口地址是你配置的,这里假设是本地的/rtmp/status
    RTMP_ACTIVE_CONN=$(curl -s "http://localhost/rtmp/status" | grep -E '^active' | awk '{print $2}')
    # 打印时间戳、RSS大小、活跃连接数,数据清晰,方便对比
    echo "$(date '+%Y-%m-%d %H:%M:%S') | RSS占用(MB): $RSS_MB | RTMP活跃连接数: $RTMP_ACTIVE_CONN"
    # 休眠1秒再采集,避免数据太密
    sleep 1
done

用的时候,把这个脚本存成monitor_rtmp.sh,然后给执行权限,运行:

chmod +x monitor_rtmp.sh
./monitor_rtmp.sh

运行之后,你就能看到每1秒的RSS和连接数变化,比如如果连接数一直稳定,RSS却每分钟涨1MB,那大概率是连接没释放或者资源没回收;如果连接数涨的时候RSS也涨,连接数降了之后RSS没降,那就是内存泄漏了。

三、核心排查思路与分步验证

3.1 排查方向一:连接数是否真的释放了?

很多时候Nginx-RTMP的连接断开了,但Nginx没把对应的内存资源释放,就会导致RSS持续涨。怎么验证?用刚才的脚本,观察当用户断开连接的时候,RTMP活跃连接数降了,RSS有没有跟着降。比如脚本运行的时候,你停掉一个正在推流的主播,看看连接数是不是从10变成9,RSS是不是从1000MB降到990MB,如果连接数降了,RSS没降,那就是连接资源没释放;如果连接数和RSS都跟着降,那连接数的问题就排除了。 另外,还要检查Nginx的RTMP配置里的超时时间,比如推流超时的设置,有没有设置合理的超时,比如推流中断后,Nginx会不会在10秒后自动断开连接,释放资源,比如用命令查看配置:

# 查看Nginx配置里的rtmp模块相关的超时设置,cat看配置文件,grep过滤相关项
cat /etc/nginx/nginx.conf | grep -A 20 'rtmp {' | grep -E 'timeout|connect|drop'

如果配置里没有设置超时,那断开的连接会一直占着内存,时间长了就会累积成大的泄漏。

3.2 排查方向二:流文件的缓存有没有清理?

Nginx-RTMP会缓存推流的文件,比如有人推流进来,Nginx会把流缓存到硬盘或者内存里,如果推流停止了,Nginx没把对应的缓存文件或者内存缓存清理,那RSS也会涨。怎么排查?比如你可以看Nginx的RTMP的缓存目录,默认是/usr/local/nginx/rtmp/cache,用命令查看这个目录的大小,以及文件是否在没有流的时候还存在:

# 查看RTMP缓存目录的总大小,单位是MB,方便看
du -sh /usr/local/nginx/rtmp/cache || echo "缓存目录不存在,请检查配置"
# 查看缓存目录里的文件,按时间排序,看有没有很久没更新的文件,说明对应的流已经停了
ls -lt /usr/local/nginx/rtmp/cache

如果目录里有很多很久没修改的文件,那就是Nginx没清理这些缓存,你可以修改Nginx的rtmp.conf,添加对应的缓存清理配置,比如设置推流停止后自动删除缓存,或者设置缓存的最大大小,超过就自动清理。

3.3 排查方向三:Nginx-RTMP模块本身的bug?

有些旧版本的Nginx-RTMP模块本身就有内存泄漏的bug,比如很多人用的1.2.1版本,就有连接资源没释放的问题,换成1.2.2或者更新的版本,问题就解决了。怎么看是不是版本问题?去Nginx-RTMP的官方GitHub页面,看release notes,找有没有关于内存泄漏的修复,或者去国内的技术论坛搜“Nginx-RTMP 内存泄漏”,看看有没有其他人遇到同样的问题,是不是模块版本导致的。比如我之前帮朋友排查过一个在线教育的直播服务器,用的是Nginx-RTMP 1.2.1,RSS每天涨200MB,换成1.2.3之后,内存就稳定了,再也没涨过。

四、应用场景、技术优缺点、注意事项

4.1 适用的应用场景

这个排查思路和方法,最适合的场景是:用Nginx-RTMP做长期运行的直播推流中转服务,比如在线教育、企业直播、小型直播平台,这些服务需要7*24小时运行,没有办法经常重启Nginx,而且流量稳定,用户群相对固定,不会突然暴涨暴跌的情况。如果是流量波动很大的直播平台,比如大促期间有几十万用户,可能还要结合其他排查方法,但核心思路还是一样的。

4.2 排查方法的优缺点

优点:① 用的都是Linux自带的工具,不用装复杂的软件,新手也能上手;② 排查步骤简单,不需要深入的Nginx源码知识,只要懂基本的命令就能操作;③ 不会影响线上服务,都是非侵入式的监控,不用重启服务,不用修改太多配置。 缺点:① 只能排查浅层的内存泄漏,比如连接没释放、缓存没清理,对于Nginx源码级别的深层泄漏,这种方法就找不到;② 脚本需要手动运行,不能长期后台监控,要长期监控的话,可以用nohup或者systemd把脚本做成后台服务。

4.3 必须注意的细节

排查的时候有几个细节一定要注意,不然会踩坑:① 不要随便重启Nginx,尤其是在高峰流量的时候,重启会导致用户掉线,影响服务质量,尽量用监控的方法先找到原因,再改配置;② 所有的配置修改,一定要先备份,比如修改nginx.conf之前,先执行cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak,改完测试没问题再替换;③ 线上排查的时候,不要乱删文件,比如缓存目录里的文件,删之前一定要确认对应的流已经停了,不然会影响正在推流的用户。

五、总结

遇到Nginx-RTMP进程RSS持续增长的问题,不要急着找运维或者开发,先自己用简单的命令和脚本排查,按照“看现象→采数据→查连接→查缓存→查版本”的思路,一步步来,大部分情况都是连接释放不及时或者缓存没清理的问题,改个配置或者换个模块版本就能解决。如果这些都试过了还是不行,那可能就是更深层的源码问题,再找专业的人帮忙。总的来说,这种内存泄漏问题是长期运行服务的常见问题,只要用对方法,就能快速解决,保障服务稳定。