136

我想知道当 web 服务器将自己描述为 pre-fork web 服务器时它到底意味着什么。我有一些例子,例如unicorn用于 ruby​​ 和gunicorn用于 python。

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

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

此外,关于独角兽/gunicorn 的更具体的问题:

假设我有一个想要与 (g)unicorn 一起运行的 web 应用程序。在初始化时,webapp 会做一些初始化工作(例如填写额外的数据库条目)。如果我用多个工作人员配置 (g)unicorn,初始化的东西会运行多次吗?

4

2 回答 2

129

预分叉基本上意味着主人创建处理每个请求的分叉。fork 是一个完全独立的 *nix 进程。

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

当您拥有非线程安全的库时,可以使用预分叉。这也意味着导致问题的请求中的问题只会影响处理它们的进程,而不影响整个服务器。

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

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

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

于 2014-09-17T15:34:41.850 回答
2

“前叉工人模型”如何工作?

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

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

  • 多处理如果您的程序只能针对一个 CPU 内核,您可能会因为只生成一台服务器而浪费一些硬件容量。分叉的工人解决了这个问题。
  • 稳定性:当一个工人崩溃时,主进程不受影响。它可以产生一个新的工人。
  • 线程安全因为它真的就像你的服务器被多次启动,在不同的进程中,你不需要担心线程安全(因为没有线程)。这意味着当您拥有非线程安全代码或使用非线程安全库时,它是一个合适的模型。
  • 速度:由于子进程不会在需要时正确分叉(生成),而是先发制人,因此服务器始终可以快速响应。

替代方案和旁注

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

来源

于 2022-01-07T18:14:10.670 回答