Linux 文件句柄的这些技术内幕,只有 1% 的人知道

简介: Linux内核暴露出来的指标对系统监控很有意义,认识这些指标背后隐含的对象以及增长原因,能够帮助我们在异常时找出问题所在。

image

1. 缘起

某个月朗风清的晚上,正在公司对面的深大操场跑步,突然接到同事发来的消息,他发现某机器上的文件句柄使用量有十一万多个(下面输出中的第一个字段)

image


但是通过运维常用的lsof命令算了下,相差甚远。

image


似乎很不科学,这里看到的数据不到1万个,剩下10多万的文件句柄哪里去了呢(系统完整性检查已排除黑客入侵可能性)

2. 文件描述符和文件句柄的故事

先看一张著名的图吧

image


这里我们先区分好两个概念:文件描述符和文件句柄

简单来说,每个进程都有一个打开的文件表(fdtable)。表中的每一项是struct file类型,包含了打开文件的一些属性比如偏移量,读写访问模式等,这是真正意义上的文件句柄。

文件描述符是一个整数。代表fdtable中的索引位置(下标),指向具体的struct file(文件句柄)。

3. file-nr 文件里的值是文件描述符还是文件句柄?

顺着内核代码找一下:

image

可以看出file-nr指标是由proc_nr_files函数处理,该函数最终其实是读取了nr_files全局变量

image

找下什么地方增加了这个值:

可以看到fs/file_table.c文件中第127行的get_empty_filp函数会增加这个值。那么这个函数是干什么的呢?

内核里面有注释“Find an unused file structure and return a pointer to it.”, 其实就是用来分配struct file的。

到此,相信你已经知道答案了。file-nr文件里面的第一个字段代表的是内核分配的struct file的个数,也就是文件句柄个数,而不是文件描述符。

4. 哪些地方会分配文件句柄?

知道文件句柄最终是通过get_empty_filp函数从filp cache中分配的之后,我们顺着函数调用链路简单梳理下,就能知道有哪些地方会分配文件句柄了:

open系统调用打开文件(path_openat内核函数)

打开一个目录(dentry_open函数)

共享内存attach (do_shmat函数)

socket套接字(sock_alloc_file函数)

管道(create_pipe_files函数)

epoll/inotify/signalfd等功能用到的匿名inode文件系统(anon_inode_getfile函数)

实际上,lsof的手册页也有部分描述:

image

5. 找出元凶

有了上面的知识,我们除了看lsof的输出之外,再通过ipcs命令看一下共享内存的情况:

image

居然有部分共享内存段被attach了9多万次,数量级对得上,毫无疑问就是它了!

可能有些同学会有疑问,同一个进程居然可以重复attach同一段共享内存那么次?答案是可以的,内核无限制。显然,这样做逻辑上是有问题的,对共享内存的正常操作,要么是attach后一直用,要么是attach用完之后就detach。

6. 排除了共享内存等的情况,我看到的file-nr值和lsof输出还是有很大差异?

上面的案例算是比较典型,然而,即便在一个比较“正常”的系统上,我们可以看到file-nr和lsof的输出还是有不小的差距的:

image

这里本质上是因为文件描述符和文件句柄是两个不同的东西:lsof在用户空间,主要还是从文件描述符的角度来看文件句柄。

我们来做一个实验:只打开一次文件,然后复制1000次文件描述符。测试代码如下:

image

image

我们启动dupfd进程打开了一次/dev/zero文件,复制了1000次文件描述符。file-nr中的文件句柄数只是个位数的变化,而lsof看到的结果涨了1000多。

如果我们把前面的代码换成open 1000次, 就可以看到file-nr和lsof的输出几乎都涨了1000。

lsof看到的是文件描述符不能代表文件句柄,还有一个有趣的例子。下面的mmap程序运行后。 文件句柄增加了将近1000, 而lsof看到的文件描述符才个位数:

image

我们来看一下测试的mmap程序代码:

image

代码中,我们循环1000次打开/dev/zero文件,之后mmap映射到进程地址空间,然后把这些打开的文件描述符都关掉。很显然,打开的描述符都被close掉了,不会有什么变化。 那为什么文件句柄数还是增加了1000个左右呢?

原来,linux内核中很多对象都是有引用计数的。 虽然文件句柄是由open先打开的,但mmap之后,引用计数被加1,尽管我们接着把文件描述符close掉了,但是底层指向的struct file由于引用数大于0,不会被回收。

通过上面两个例子,你应该知道lsof的输出和实际的文件句柄数有差距的原因了。

7. 如何找出内存映射间接占用的文件句柄?

实际上,不管是mmap映射文件,还是通过shmat连共享内存,最终都会在进程地址空间中分配一片内存区。 通过pmap命令可以看出一些端倪:

image

回到故事的开头。那个使用了11万文件句柄的机器,在内核slab cache中,除了文件句柄(struct file对象)对应的filp cache对象多之外,对应的内存区对象vm_area_struct占用也是超多的.
下面是slabtop的部分输出:

image

8. 还有其他lsof漏掉的情况吗?

当然有了,lsof是通过查看进程的内存映射和文件描述符表来枚举打开文件的, 如果是一个多线程的服务。主线程先退出了,子线程还活着, 那么进程的fd表看起来就是空的。

image

9. 总结
Linux内核暴露出来的指标对系统监控很有意义,认识这些指标背后隐含的对象以及增长原因,能够帮助我们在异常时找出问题所在。

原文发布时间为:2018-07-24
本文作者:高效运维
本文来自云栖社区合作伙伴“高效运维”,了解相关信息可以关注“高效运维

相关文章
|
1月前
|
Linux 数据安全/隐私保护 虚拟化
Linux技术基础(1)——操作系统的安装
本文是龙蜥操作系统(Anolis OS) 8.4 的安装指南,用户可以从[龙蜥社区下载页面](https://openanolis.cn/download)获取ISO镜像。安装方法包括物理机的光驱和USB闪存方式,以及虚拟机中的VMware Workstation Pro设置。安装过程涉及选择语言、配置安装目标、选择软件集合和内核,设置Root密码及创建新用户。安装完成后,可通过文本模式或图形化界面验证系统版本,如Anolis OS 8.4,标志着安装成功。
|
1月前
|
Linux 数据处理 C++
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用(一)
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用
71 0
|
1月前
|
存储 Linux API
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用(三)
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用
31 1
|
1月前
|
消息中间件 Linux 数据处理
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用(二)
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用
32 1
|
3月前
|
监控 Linux Shell
【Linux技术专题】「夯实基本功系列」带你一同学习和实践操作Linux服务器必学的Shell指令(排查问题指令 - 下)
在线上排查问题时,查询日志、查看系统配置和分析操作系统信息是至关重要的。这些操作可以帮助我们深入了解软件和服务的兼容性,并解决潜在的问题。在本次学习中,我们将介绍并深入学习一些我在处理类似问题时常用的指令。通过掌握这些指令,你将能够更加高效地定位和解决线上问题,提高系统的稳定性和性能。让我们一同进入这个学习过程吧!
43 0
【Linux技术专题】「夯实基本功系列」带你一同学习和实践操作Linux服务器必学的Shell指令(排查问题指令 - 下)
|
29天前
|
弹性计算 Linux Shell
Linux技术基础(2)——文本处理
文本处理实验:探索[Vim](https://developer.aliyun.com/adc/scenario/aced2264751f4866a8340de4cf9db0fa)的命令、输入和底线模式,学习文本编辑快捷操作,如光标移动、删除、复制和粘贴。了解如何使用底线命令模式进行文件保存、退出及搜索替换。同时,掌握`cat`、`more`、`less`、`head`、`tail`等文本查看命令,以及`stat`、`wc`、`file`、`diff`等文件处理命令。利用`grep`、`sed`、`awk`和`cut`进行文本搜索、替换和分析。
|
5月前
|
存储 Linux Docker
跨cpu架构部署容器技术点:怎样修改Linux 的内核版本
在使用Docker 进行跨平台部署之后,我们还可以尝试进行跨架构部署。 从X86 架构上移植到 aarch64 上。
199 0
|
6月前
|
人工智能 弹性计算 并行计算
操作系统迁移难?Alibaba Cloud Linux 支持跨版本升级 | 龙蜥技术
无需担心数据丢失,无需考虑如何解决在升级后同步问题。
|
6月前
|
Linux
Linux 神奇命令大合集:掌控操作系统,成为技术达人!
Linux 神奇命令大合集:掌控操作系统,成为技术达人!
81 1
|
3月前
|
安全 Linux 测试技术
深入Kali Linux:高级渗透测试技术详解
深入Kali Linux:高级渗透测试技术详解
170 0