多进程VS多线程服务器最受益的是什么?

时间:2013-09-02 14:13:01

标签: ruby-on-rails ruby multithreading unicorn puma

任何人都可以解释每种并发方法的瓶颈是什么吗?

独角兽(基于流程)的服务器 Puma (基于线程)。

每种方法都更喜欢CPU内核吗?线程?或者只是时钟速度?还是一个特殊的组合?

如何确定使用专用服务器时所需的最佳CPU特性?

以及如何确定Unicorn案例中的最佳工人金额,或者在Puma的情况下确定线程金额?

2 个答案:

答案 0 :(得分:56)

Unicorn是基于流程的,这意味着ruby的每个实例都必须在其自己的进程中存在 。对于每个进程,这可能在500mb的范围内,这将很快耗尽系统资源。 Puma,基于线程,不会使用相同数量的内存来理论上达到相同的并发量。

Unicorn ,即运行多个进程,将在不同进程之间具有并行性。这受到CPU内核的限制(更多内核可以同时运行更多进程),但内核将在活动进程之间切换,因此可以运行4到8个进程(无论您拥有多少个进程)。您将受到机器内存的限制。直到最近,ruby还没有写入时友好,这意味着每个进程都有自己的继承内存(unicorn是一个preforking服务器)。 Ruby 2.0是写时复制友好的,这可能意味着独角兽实际上不必在内存中加载所有子进程。我不是100%清楚这一点。阅读有关写作的副本,并查看jessie storimer的“使用unix进程”这本很棒的书。我很确定他已经把它覆盖了。

Puma是一个线程服务器。 MRI Ruby,由于全局解释器锁(GIL),一次只能运行一个CPU绑定任务(参见ruby tapas第127集,parallel fib)。它将在线程之间进行上下文切换,但只要它是一个CPU绑定任务(例如数据处理),它就只会运行一个执行线程。如果您使用不同的Ruby实现(如JRuby或Rubinius)运行服务器,这会很有趣。他们没有GIL,可以并行处理大量信息。 JRuby非常快,虽然Rubinius与MRI相比较慢,但多线程Rubinius处理数据的速度比MRI快。然而,在非阻塞IO期间(例如写入数据库,发出Web请求),MRI将上下文切换到非执行线程并在那里工作,然后在返回信息时切换回前一个线程。

对于 Unicorn ,我会说瓶颈是内存和时钟速度。对于 Puma ,我会说瓶颈是您选择的解释器(MRI vs Rubinius或JRuby)以及服务器正在进行的工作类型(许多cpu绑定任务与非阻塞IO)。 / p>

这场辩论有很多很好的资源。查看Jessie Storimer关于这些主题的书籍working with ruby threadsworking with unix processes;来自ryan tomayko的read this quick summary of preforking servers,以及谷歌周围的更多信息。

我不知道你的情况下Unicorn或Puma的最佳工人数量是多少。最好的办法是运行性能测试并做适合您的事情。没有一种尺寸适合所有人。 (虽然我认为美洲狮标准是使用16个线程的池并锁定它)

答案 1 :(得分:5)

Puma实际上是多线程和多进程的。您可以在“群集模式”中调用它,它将生成多个分叉的工作人员,这些工作人员将在MRI上的不同核心上运行。由于Puma是多线程的,因此可能适合运行与服务器上的核心数相等的多个进程。因此,对于4核服务器来说,这样的事情是合适的:

puma -t 8:32 -w 4 --preload

这将处理多达32个并发线程,同时在CPU上运行最多4个线程,并且应该能够最大化服务器上​​的CPU资源。 --preload参数预加载应用程序并利用ruby 2.0 COW对垃圾收集的改进来减少RAM使用。

如果您的应用花费大量时间等待其他服务(搜索服务,数据库等),那么这将是一个很大的改进。当一个线程阻塞时,同一进程中的另一个线程可以抓住CPU并继续工作。在此示例中,您最多可以并行支持32个请求,而只需要在RAM中运行4个进程。

使用Unicorn,您将不得不分叉32个工作人员,这将在RAM中运行32个进程,这非常浪费。

如果您的所有应用程序都是CPU运算,那么这将是非常低效的,您应该减少独角兽的数量,并且Puma优于Unicorn的好处将会减少。但在Unicorn案例中,您必须对应用程序进行基准测试并找出正确的数字。 Puma将倾向于通过产生更多线程来优化自身,其性能应该不低于Unicorn(在纯CPU情况下)到比Unicorn好得多(在应用程序睡眠很多的情况下)。

当然如果您使用Rubinius或JRuby,那么它就没有竞争对手,您可以生成一个运行多核并处理所有32个线程的进程。

TL; DR是因为Puma实际上使用这两种模型,所以我认为Unicorn不会优于Puma。

当然,我对Puma vs Unicorn在现实世界中运行生产软件的可靠性一无所知。需要关注的一件事是,如果你在一个线程中乱写任何全局状态,它可能会影响同时执行的其他请求,这可能会产生不确定的结果。由于Unicorn不使用线程,因此没有并发问题。我希望到目前为止,Puma和Rails在并发问题方面都很成熟,并且Puma可用于生产。但是,我不一定希望我在GitHub上找到的每个rails插件和rubygem都是线程安全的,并且预计还需要做一些额外的工作。但是,一旦你成功地在第三方库中找到线程问题,你可能已经足够大,以至于你无法负担运行这么多Unicorn进程的RAM成本。 OTOH,我理解并发错误,我对Ruby很好,因此调试成本对我来说可能比在云中购买RAM的成本要低得多。 YMMV。

另请注意,我不确定您是否应该计算超线程内核或物理内核来估算传递给'-w'的值,并且您需要自己进行性能测试,以及性能测试要使用的值-t。虽然即使你运行的进程数量是你需要的两倍,但是内核中的进程调度程序应该能够毫无困难地处理它,直到你使CPU饱和为止,无论如何你都会遇到更大的问题。我可能会建议为每个超线程核心启动一个过程(在MRI上)。