【问题标题】:What exactly is a pre-fork web server model?什么是 pre-fork Web 服务器模型?
【发布时间】:2014-11-08 04:05:06
【问题描述】:

我想知道当网络服务器将自己描述为分叉前网络服务器时究竟意味着什么。我有几个例子,比如unicorn 用于 ruby​​,gunicorn 用于 python。

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

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

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

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

【问题讨论】:

    标签: apache webserver unicorn gunicorn preforking


    【解决方案1】:

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

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

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

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

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

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

    【讨论】:

    • 我对“prefork”的含义也有同样的疑问。我想这自然意味着某种分叉,但“前”部分让我感到困惑。我在这里abbreviations.com/prefork 发现“pre”部分实际上意味着工作进程是预先创建的,因此只有在需要工作人员时才不会浪费时间。对我来说很有意义:)
    • // ,@ElNinjaTrepador,为什么不添加单独的答案?至少,这对我来说更容易理解,如果该评论获得更突出的位置,它可能对其他人有更大的帮助。
    • 我已经更新了答案,在 pre-fork 中添加了更多关于 pre 的信息。 @ElNinjaTrepador 感谢您指出这一点,我没有意识到这并不为人所知。
    • @NathanBasanese 会做先生 ;)
    • @JoeDoherty 也许它是众所周知的,直到那时我才知道它:DI 将添加另一个答案(根据 Nathan 的要求),但既然你已经添加了我对你说没有必要了:)
    【解决方案2】:

    “pre-fork worker 模型”如何工作?

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

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

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

    替代方案和旁注

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

    来源

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-01-19
      • 2016-04-02
      • 2013-11-06
      • 2019-01-28
      • 1970-01-01
      • 2012-04-06
      相关资源
      最近更新 更多