什么是前叉网络服务器模型?

我想知道,当一个网络服务器将自己描述为一个前叉网络服务器时,它到底意味着什么。我有一些例子,比如 Ruby 的 独角兽和 python 的 枪角兽

更具体地说,这些问题是:

  • 这个模型解决了什么问题?
  • 当 pre-fork Web 服务器最初启动时会发生什么?
  • 它如何处理请求?

还有一个更具体的问题,关于独角兽/枪独角兽:

假设我有一个网络应用程序,我想与(g)独角兽一起运行。在初始化时,webapp 会做一些初始化工作(例如,填入额外的数据库条目)。如果我配置(g)麒麟与多个工作者,将初始化的东西运行多次?

31240 次浏览

Pre-forking 基本上意味着一个主创建分叉来处理每个请求。

根据下面的评论更新。pre-fork中的 pre意味着这些进程在请求进入之前被分叉。然而,它们通常可以随着负载的上升和下降而增加或减少。

当您有不是线程安全的库时,可以使用预分叉。它还意味着在请求中引起问题的问题只会影响处理它们的进程,而不会影响整个服务器。

运行多次的初始化完全取决于您正在部署的内容。然而,通常每个进程都会存在连接池和类似的东西。

在线程模型中,主线程也会创建更轻量级的线程来分派请求。但是如果一个线程导致了大量的问题,它可能会对主流程产生影响。

使用 Nginx、 Apache 2.4的 Event MPM 或 gevent (可以与 Gunicorn 一起使用)等工具,这些都是异步的,这意味着一个进程可以在不阻塞的情况下处理数百个请求。

“前叉工模式”是如何运作的?

  • 主进程 : 有一个主进程生成并杀死工作者,具体取决于硬件的负载和容量。更多的传入请求将导致主服务器产生更多的工作者,直到达到“硬件限制”(例如,所有 CPU 饱和) ,此时将设置队列。
  • Workers : worker 可以理解为您的应用程序/服务器的实例。因此,如果有4个工作人员,您的服务器将启动4次。这意味着它占用4倍的“基本内存”比只有一个工作人员,除非你做共享内存向导。
  • 初始化 : 您的初始化逻辑需要足够稳定,以适应多个服务器。例如,如果编写 db 条目,检查它们是否已经存在,或者在应用服务器之前添加安装作业
  • Pre-fork : prefork 中的“ pre”意味着主服务器总是比当前所需要的容量多一点,这样,如果负载上升,系统就“已经准备好了”。因此,它产生了一些工人。例如,在 这个 apache 库中,您可以使用 MinSpareServers属性控制它。
  • 请求 : 请求(TCP 连接句柄)从主进程传递给子进程。

Pre-fork 服务器解决什么问题?

  • 多处理 : 如果您有一个只能针对一个 CPU 核的程序,那么只生成一个服务器可能会浪费一些硬件容量。分叉工人解决了这个问题。
  • 稳定性: 当一个工作者崩溃时,主进程不会受到影响,它只会产生一个新的工作者。
  • 线程安全 : 由于实际上就像您的服务器被多次引导一样,在单独的进程中,您不需要担心线程安全(因为没有线程)。这意味着当您有非线程安全的代码或使用非线程安全的库时,它是一个合适的模型。
  • 速度: 由于子进程在需要时没有正确分叉(派生) ,但是服务器总是能够提前做出快速响应。

备选方案及旁注

  • 容器编排: 如果你熟悉集装箱化和容器编排工具,比如 库伯内特,你会发现很多问题都是通过这些工具解决的。Kubernetes 产生多个豆荚用于多处理,它具有相同(或更好)的稳定性和“水平豆荚自动缩放器”之类的东西,也产生和杀死工人。
  • 线程 : 服务器可能为每个传入请求产生一个线程,这允许“同时”处理多个请求。这是大多数基于 Java 的 Web 服务器的默认设置,因为 Java 本身对线程有很好的支持。良好的支持意味着线程在不同的 CPU 核心上真正地并行运行。另一方面,Python 的线程不能真正并行化(将工作分散到多个内核) ,因为它们只提供了一种上下文切换的 GIL。更多关于 给你的信息。这就是为什么对于像 gunicorn 这样的 Python 服务器“ pre-forkers”如此流行的原因,而来自 Java 的人可能以前从未听说过这样的事情。
  • Async/非阻塞处理 : 如果您的服务器花费大量时间“等待”,例如磁盘 I/O、对外部服务的 http 请求或数据库请求,那么多处理可能不是您想要的。相反,应该考虑让代码“非阻塞”,这意味着它可以同时处理多个请求。基于 Async/wait (coroutines)的系统,如 python、 Go 或 nodejs 中的 fastapi (asgi server) ,使用这种机制,即使一个服务器也可以同时处理多个请求。
  • CPU 绑定任务: 如果您有 CPU 绑定任务,上面提到的非阻塞处理不会有多大帮助。然后,您将需要某种多处理方法来分配 CPU 核上的负载,正如上面提到的解决方案,即: 容器编排、线程(在允许真正并行化的系统上)或... 预分叉工作器。

消息来源