Puma 实际上是多线程和多进程的。您可以在“集群模式”中调用它,它会产生多个分叉的工作人员,这些工作人员将在 MRI 的不同核心上运行。由于 Puma 是多线程的,它可能适合运行与服务器上的内核数相等的进程数。所以对于一个 4 核服务器来说,这样的东西是合适的:
puma -t 8:32 -w 4 --preload
这将处理多达 32 个并发线程,其中多达 4 个线程同时在 CPU 上运行,并且应该能够最大限度地利用服务器上的 CPU 资源。 --preload 参数预加载应用程序并利用 ruby 2.0 COW 对垃圾收集的改进来减少 RAM 使用。
如果您的应用花费大量时间等待其他服务(搜索服务、数据库等),那么这将是一个很大的改进。当一个线程阻塞时,同一进程中的另一个线程可以抢占 CPU 并开始工作。在此示例中,您最多可以并行支持 32 个请求,而仅在 RAM 中运行 4 个进程。
如果使用 Unicorn,您将不得不分叉 32 个工作人员,这将承受在 RAM 中运行 32 个进程的影响,这是非常浪费的。
如果您的应用程序所做的只是 CPU 运算,那么这将非常低效,您应该减少独角兽的数量,而 Puma 相对于独角兽的优势将会降低。但在 Unicorn 案例中,您必须对您的应用程序进行基准测试并找出正确的数字。 Puma 将倾向于通过产生更多线程来优化自身,其性能范围应该从不比 Unicorn 差(在纯 CPU 情况下)到比 Unicorn 好得多(在应用程序休眠很多的情况下)。
当然,如果您使用 Rubinius 或 JRuby,那么就没有什么可竞争的了,您可以生成一个运行多核并处理所有 32 个线程的进程。
TL;DR 是我不认为 Unicorn 比 Puma 有太多优势,因为 Puma 实际上使用了这两种模型。
当然,我对 Puma vs Unicorn 在现实世界中运行生产软件的可靠性一无所知。需要关注的一件事是,如果您在一个线程中随意涂抹任何全局状态,它可能会影响同时执行的其他请求,这可能会产生不确定的结果。由于 Unicorn 不使用线程,因此不存在并发问题。我希望此时 Puma 和 Rails 在并发问题方面都已经成熟,并且 Puma 可以在生产中使用。但是,我不一定希望我在 GitHub 上找到的每个 rails 插件和 rubygem 都是线程安全的,并且希望必须做一些额外的工作。但是,一旦您成功地在第三方库中发现线程问题,您可能已经足够大,以至于您无法负担运行这么多 Unicorn 进程的 RAM 成本。 OTOH,我了解并发错误并且我对 Ruby 很熟悉,因此调试成本对我来说可能比在云中购买 RAM 的成本要低得多。 YMMV。
另外请注意,我不确定您是否应该计算超线程内核或物理内核来估算传递给“-w”的值,并且您需要自己进行性能测试,以及性能测试要使用的值-t。尽管即使您运行的进程数量是您“需要”的两倍,但内核中的进程调度程序应该能够毫无问题地处理该问题,直到您的 CPU 饱和,在这种情况下,无论如何您都会遇到更大的问题。我可能会建议为每个超线程内核启动一个进程(在 MRI 上)。