我目前对 Linux(内核)名称空间的理解是,它们创建后的生命周期只要满足以下条件之一即可:
- 至少一个进程/线程已加入(附加,...)到命名空间 X。
- 命名空间 X 至少存在一个绑定挂载。
- 至少存在一个引用命名空间 X 的开放 fd。
- 对于用户/PID 命名空间:X 中至少存在一个子命名空间 Y。
我天真地认为,当上述条件不再成立时,Linux 内核就会“尽快”销毁命名空间。然而,我注意到命名空间变得过时和被破坏之间存在一些延迟......如果我没有记错的话,就是这样。
下面的 Python3 小脚本创建了一系列新的网络名称空间,并立即进入每个名称空间,留下前一个名称空间。由于没有其他进程和线程保存对先前创建的网络命名空间的任何引用,因此它变得过时并最终应该消失。一个间接的标志是命名空间 inode 编号会被重用。
现在请注意该脚本如何以两个顺序创建“临时”网络名称空间:一次以缓慢的方式,中间有很多空闲时间,一次以快速的方式......
import unshare
import os
import time
def trash(delay):
for i in range(4):
unshare.unshare(unshare.CLONE_NEWNET)
print('trash net:[%d]' % os.stat('/proc/self/ns/net').st_ino)
time.sleep(delay) # wait for penguins to collect garbage namespaces
# user namespaces can be created by unprivileged processes
# (unless on mispatched Debian kernels): this gives us all
# capabilities inside this new user namespace owned by our
# user, so we can create other namespaces.
unshare.unshare(unshare.CLONE_NEWUSER)
print('original net:[%d]' % os.stat('/proc/self/ns/net').st_ino)
print('slow trashing...')
trash(0.5)
time.sleep(0.5)
print('fast trashing...')
trash(0.01)
运行时,您的输出应类似于以下内容:
$ python3 nsgarbage.py
original net:[4026531905]
slow trashing...
trash net:[4026532268]
trash net:[4026532344]
trash net:[4026532268]
trash net:[4026532344]
fast trashing...
trash net:[4026532268]
trash net:[4026532419]
trash net:[4026532494]
trash net:[4026532569]
请注意,在延迟 0.5 秒的缓慢序列中,过时的网络命名空间如何被销毁,并且它们的 inode 编号被重用:新创建的网络命名空间的 inode 编号会发生振荡。
相反,对于快速序列,过时的命名空间似乎不会被破坏(垃圾收集),正如它们的索引节点号没有被重用所表明的那样,而是“堆积”。
请注意,我只能根据索引节点号的重用间接推断命名空间何时被破坏。这可能是错误的假设。
具有 Linux 内核知识的人能否更深入地了解 Linux 的行为:内核何时真正破坏命名空间?如果销毁被延迟,这种“垃圾收集”是否存在某种内在的粒度?
答案1
第一的,这是“什么是 NSFS 文件系统?”的答案进一步阐明了 Linux 内核如何管理命名空间生命周期:使用 proc 文件系统内部引入的所谓“nsfs”文件系统。因此,当其 inode 不再被其中一个元素引用时,命名空间就准备好被销毁了这个问题中提到。
事实证明,网络命名空间在销毁(清理)方面似乎特别复杂。网络命名空间的管理是在净/核心/net_namespace.c。
吸引眼球的一件事是用于清理网络命名空间的工作队列的定义:
static DECLARE_WORK(net_cleanup_work, cleanup_net);
工作队列(linux-kernel-labs.github.io Lab) 在很多地方都被用来安排可能阻塞的操作在进程上下文中运行。然后,清理网络命名空间由内核工作线程处理,该线程还服务于其他工作队列,另请参阅 Linux 内核文档并发管理工作队列 (cmwq)了解更多工作队列背景信息。
快速浏览一下其他名称空间管理实现(使用fs/proc/命名空间.c作为一个好人,呃,蹦床到特定的实现中)并不表明需要使用工作队列进行名称空间清理。