最近在做流媒体相关的一些服务,它通过 k3s 部署在盒子上,我们的服务偶尔会出现拉流资源被拉爆的情况,需要定位一下是否存在资源泄漏的情况。由于基本流媒体服务是端口复用的,我们则选择 lsof -i :
lsof -i :
这是最直观的工具,可以看到针对这个 port 有打开哪些资源,但是在我们现在这个环境下失效了,什么都没有输出。但是系统又是 work 的,信息到底隐藏到哪里了呢?
/proc/net/tcp
linux proc 伪文件系统提供了很多有意思的功能,例如这个文件就记录着系统里目前运行着的 tcp 链接,那么我们尝试读取这个文件,由于这个文件记录的数据是 16 进制的,进行 grep 时,我们需要转换一下,我这里的端口是 9500,转换后是 251C。 关于 tcp 文件的细节,可以参考 https://www.kernel.org/doc/Documentation/networking/proc_net_tcp.txt。
$ cat /proc/net/tcp | grep 251c
返回是空白的,什么数据都没有,只能再尝试别的方法了。
/proc/
系统里什么都看不到,只能继续去对应的进程的空间里看看了,fd 是最常用的 ,我们能看到很多数据,一些 socket,一些 file,但是并无法知道 socket 到底是什么,是一个 unix socket 还是别的什么,也看不到端口。

那么 /proc/
哈,果然在这里,能看到打开的 251C 的链接了,通过这里我们能够看到真实 work 的数据了。
WHY
为什么会这样?
本身问题也比较简单,要搞明白这个问题,需要了解这些网络相关的东西,做容器的同学应该都听说过 iptables 和 linux namespaces。后者为每个容器划分独立的网络空间,而 iptables 提供转发的功能。这里我们不深入讨论这两个系统,了解即可。
/proc/net/tcp 的问题是,如果是在 namespace 里打开的链接,在这里就不会体现了。进程在 net namespace 中监听端口,iptables 将收到的网络数据进行转发。
既然知道是 namespace,一切都简单了,我们有 nsenter 工具,以及对应的 namespace
$ nsenter --net /proc/<pid>/ns/net -- lsof -i :9500

至此,完美解决问题,不需要再登进容器 apt update && apt install lsof 了。
建议大家去熟悉 proc 各个功能,在监控不足的环境下定位问题,有奇效。