← 返回信息流
AI 资讯Hacker News·2 天前

超越 Fork 与 Exec:操作系统进程创建机制的演进

原标题:Moving Beyond Fork() + Exec()

速览

文章深入分析了传统 Unix 系统中 Fork 和 Exec 系统调用在进程创建中的局限性,特别是在内存复制和启动延迟方面。随着现代应用对性能要求的提升,业界正在探索基于 Copy-on-Write 优化、直接映射或全新架构的替代方案。这一转变旨在显著降低系统开销,提升云原生环境下的资源利用率和应用启动速度。

AI 深度解读

超越 fork() + exec():Linux 进程创建机制的演进与反思

背景

在操作系统中,fork() 是一个相对昂贵的系统调用。为了创建子进程,内核必须复制整个进程的状态,包括内存空间。尽管多年来针对这一机制进行了诸多优化,但 fork() 本质上仍然是一项高成本的操作。

更糟糕的是,在大多数应用场景中,fork() 调用之后会立即跟随一个 exec() 调用。exec() 的作用是加载并执行新的可执行文件,这意味着之前 fork() 辛苦复制的所有内存数据将被立即丢弃。这种“先复制再丢弃”的模式造成了巨大的资源浪费。

历史上,开发者曾尝试通过 vfork() 等机制来优化这一特定场景,但 fork() + exec() 的模式依然比其理论上的最低开销要昂贵得多。这一长期存在的性能瓶颈,促使 Linux 内核社区不断探索更高效的进程创建方式。

核心内容

近期,Chen 提交了一组补丁集,提出了一种名为“Spawn Templates”(生成模板)的新方法,旨在优化重复执行同一可执行文件的场景。与此同时,内核维护者 Mateusz Guzik 和 Christian Brauner 等核心开发者对该方案进行了深入审查,并提出了更具根本性的替代方案——基于 pidfdposix_spawn() 实现。

Chen 的“生成模板”方案

Chen 的方案主要针对那些需要反复启动相同可执行文件的应用程序。例如,一个程序可能需要多次运行 Git 以获取仓库信息。在这种情况下,程序可以建立一个“模板”,将设置成本分摊到多次操作中。

该方案引入了两个新的系统调用:

  1. spawn_template_create():用于创建模板。

    • 该调用返回一个文件描述符(fd),代表可执行文件的模板。
    • 内核会打开指定的文件(通过 execfdfilename),并缓存大量信息,以便未来能更快地运行该文件。
    • 结构体 spawn_template_create_args 包含标志位、执行文件描述符、标志位以及文件名等字段。
  2. spawn_template_spawn():用于基于模板生成新进程。

    • 每次执行的具体参数(如命令行参数 argv、环境变量 envp)通过 spawn_template_spawn_args 结构体传入。
    • 文件描述符更改、信号处理等特定操作通过 actions 数组传递,该数组由 spawn_template_action 结构组成,支持关闭 fd、复制 fd、打开文件、更改工作目录等操作。

性能表现: Chen 提供的基准测试显示,该方案带来了约 2% 的性能提升。虽然看似不多,但对于符合该模式的特定应用而言,这一优化是有意义的。

社区反馈与更深层的讨论

尽管 Chen 的方案提供了一定优化,但 Linux 内核维护者认为这并未触及问题的核心。

Mateusz Guzik 的观点: Guzik 指出,fork() + exec 这一习语本身是糟糕的,应当被淘汰。他认为 Chen 的补丁集有些奇怪,因为它保留了 fork() 部分,而 fork() 才是成本的主要来源。他主张“创建一个纯净的进程(pristine process)”才是正途,即完全避免复制当前进程状态。

Christian Brauner 的建议: Brauner 对“为 exec 构建构建器 API”的想法表示支持,但他建议基于现有的 pidfd 抽象层来构建新 API,而不是沿用 Chen 的路径。

  • 新 API 构想:通过 pidfd_open() 创建一个空进程选项,随后通过一系列 pidfd_config() 系统调用配置该进程(设置环境、镜像、信号处理等)。
  • 类比pidfd_config() 的行为类似于 fsconfig()
  • 核心目标:新接口必须支持在用户空间实现 posix_spawn()posix_spawn()fork()/exec() 的理想替代品,但目前的实现往往在底层隐藏了 fork()exec(),开发者希望看到一个原生的、透明的实现。

最终结论

Chen 接受了 Brauner 提出的更广泛 API 设计思路,并表示未来的工作将朝这个方向发展。这意味着:

  1. Linux 内核中不会合并 Chen 的“spawn templates”补丁。
  2. 未来 Linux 可能会获得一个真正的、原生的 posix_spawn() 实现,从而从根本上解决 fork() + exec() 的性能和架构问题。

关键要点

  • 性能瓶颈fork() 复制整个进程状态(包括内存)成本高昂,且常因随后的 exec() 导致数据被丢弃,造成浪费。
  • Chen 的尝试:通过“生成模板”缓存可执行文件信息,减少重复启动相同程序时的开销,实测性能提升约 2%。
  • 核心批评:Chen 的方案未解决 fork() 本身的复制成本,Mateusz Guzik 指出应直接创建“纯净进程”而非复制。
  • Brauner 的愿景:基于 pidfd 构建新的配置 API(如 pidfd_config()),旨在支持用户空间的原生 posix_spawn() 实现。
  • 最终走向:Chen 的方案被搁置,Linux 内核未来的方向是开发基于 pidfd 的原生 posix_spawn(),以彻底取代传统的 fork()/exec() 模式。

意义与影响

这一讨论反映了 Linux 内核在系统调用设计上的成熟与反思。fork()/exec() 是 Unix 哲学的基石,但其实现效率在现代计算场景下已显捉襟见肘。

  1. 从“修补”到“重构”:Chen 的方案是一种优化补丁,而 Brauner 和 Guzik 推动的则是架构层面的重构。这表明内核维护者更倾向于从根本上消除低效模式,而非在旧模式上打补丁。
  2. posix_spawn() 的复兴:POSIX 标准早已定义了 posix_spawn(),旨在解决 fork()/exec() 的问题,但长期以来缺乏高效的底层支持。Linux 若能提供原生的、基于 pidfd 的实现,将显著提升容器启动、微服务架构中进程创建的性能。
  3. pidfd 的重要性提升:此次讨论凸显了 pidfd(进程文件描述符)作为现代 Linux 进程管理核心抽象的价值。它允许更细粒度的进程控制,为未来更复杂的进程创建和配置机制奠定了基础。
  4. 对开发者的启示:对于需要高频创建进程的应用开发者而言,关注内核对 posix_spawn() 的原生支持将是提升性能的关键。未来,开发者可能不再需要手动处理复杂的 fork/exec 逻辑,而是通过更高级、更高效的 API 来管理进程生命周期。
查看原文 →lwn.net