【问题标题】:Does it make sense to run more PHP-FPM children than number of CPU cores?运行比 CPU 内核数量更多的 PHP-FPM 子代有意义吗?
【发布时间】:2022-06-16 07:29:07
【问题描述】:

假设我有一个具有 4 个内核和 4 个线程的 CPU,运行例如是否有意义?通过设置pm.max_children = 8 选项,8 个 PHP-FPM 工作人员?就我而言,具有 4 个线程的 CPU 最多只能“真正”并行运行 4 个进程。如果这 8 个进程之间的上下文切换导致 CPU 时间丢失,会不会造成开销?

相比之下,Node.js 集群模式文档建议运行与内核数量一样多的工作程序/子程序。相同的建议在这里不适用吗?

【问题讨论】:

    标签: php operating-system cpu scheduling fpm


    【解决方案1】:

    一般的答案是肯定的,因为虽然您不能并行运行那么多线程,但您可以同时运行它们

    要理解的关键是,在大多数实际应用程序中,处理请求所花费的大量时间并没有花费在本地 CPU 上——而是花费在等待数据库查询、外部 API 甚至磁盘访问上。如果每个 CPU 核心有一个线程,那么 CPU 一直处于空闲状态。允许额外的线程,一个可以使用 CPU,而另一个正在等待外部数据。

    只有当您的应用程序非常不寻常并且将 100% 的时间花在使用 CPU 上时,每个内核只有一个线程才有意义。

    这不适用于 node.js 的原因是它使用 异步 代码在单个线程内实现并发:你可以告诉当前线程“开始做这个,在等待结果的同时,继续处理不同的请求”。这在原生 PHP 中是不可能的,它使用“无共享”方法——每个请求都有自己的线程或进程——但是 Swoole 和 Amp 等项目添加了对这种异步方法的支持。

    【讨论】:

    • 谢谢。现在似乎更清楚了,尤其是 PHP-FPM 部分。但是,我仍然不确定如果我运行每个核心 2 个 Node.js 进程会发生什么。几乎到处都提到它可能会降低性能,因为进程必须“争夺”CPU时间。这与每个内核运行多个 PHP-FPM 工作器有何不同,即 PHP-FPM 进程在连接到同一个内核时不必“争夺” CPU 时间?
    • @Artur 如果线程处于空闲状态,等待您的数据库返回一些结果,那么它不需要“争取”任何东西;这在 PHP-FPM 中会经常发生,但在 node.js 中基本上不会发生,因为 node.js 线程会在等待时接收另一个请求,并继续使用 CPU。另外,“打架”可能给人错误的印象,因为他们并没有积极地试图取代对方;它更像是“在 CPU 尝试公平地花费时间时,反复被告知要在队列中等待”。
    【解决方案2】:

    接受的答案很好,但没有正确解决问题。

    PHP 不使用线程并在单核上运行。 PHP-FPM 产生了许多工作人员,因此您可以在多个内核上运行您的进程。

    了解操作系统如何使用进程上下文切换来同时处理多个进程非常重要。如果您只有一个内核,您仍然可以同时在您的机器上运行多个进程,原因是进程上下文切换。这意味着操作系统将使用单核并在进程之间动态切换,根据各种因素一次处理每个进程,例如,如果一个进程正在等待一些 I/O,该进程已经运行了多长时间,如果另一个进程作为更高的优先级等。重要的部分是进程上下文切换需要一些时间,并且单个核心在多个进程之间共享。

    如果您有多个核心,则可以在每个核心上并行执行进程,但是很可能您的运行进程仍然比核心多,因此进程上下文切换仍然会发生,只是频率较低。

    建议将pm.max_children 设置为高于您的 CPU 内核的值的原因是,在大多数情况下,您的 php 进程并没有执行密集的 CPU 任务,而是主要等待 I/O,例如等待SQL 结果,等待一些 curl 响应或一些磁盘读写响应。这些操作称为 I/O 阻塞,通常是请求中大部分时间消耗的。通过将pm.max_children 设置为比核心更高的值(有时甚至是核心数量的 5-10 倍),您可以受益于在进程处于阻塞/空闲状态时操作系统将执行的上下文切换。

    很可能有超过 20 个 PHP 进程正在运行,只是等待 IO。如果您将pm.max_children 设置为核心数,假设为 8,那么核心可能不会做太多事情,大量请求会堆积如山,响应速度会很慢。

    如果您确定您的 php 进程没有阻塞 I/O 并且仅执行一些计算,那么您实际上可能会从仅设置与您的核心一样多的 pm.max_children 中受益更多,原因是该进程上下文切换会减慢速度,并且拥有更多正在运行的进程会占用更多资源。然而,这种情况并不常见,您的进程很可能确实存在 I/O 阻塞和空闲时间。

    有一篇很好的文章深入探讨了 Linux here 上的进程上下文切换。

    swoole PHP 扩展中还使用了一种称为协程的东西。协程也使用上下文切换来执行并发,但是这是以编程方式完成的,消耗的资源少得多,并且比操作系统上下文切换快得多。如果使用 swoole,则不需要 php-fpm,因为它更快,但它还有其他问题需要您关心。但是,使用 swoole 时,建议您设置与内核一样多的工作线程,以避免操作系统上下文切换。您可以拥有数千个协程,而不会对性能造成太大影响。

    Nodejs 使用类似于 swoole 协程的事件循环。建议设置工作线程以匹配您的内核的原因是避免操作系统上下文切换并使用内置的上下文切换,因为它更快更轻。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-11-29
      • 2012-03-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多