Ruby on Rails 服务器选项

597

为我的 Ruby on Rails 应用程序设置开发服务器的整个问题让我感到困惑。有 WEBrick、Mongrel、Passenger、Apache 和 Nginx 等等,我并不真正理解它们所扮演的不同角色。

我最初使用 WEBrick,现在在开发中使用 Mongrel。这些服务器是独立运行的,还是要在 Apache 前面运行?

我了解了 Passenger,但不是很明白它是什么。该网站上写道“轻松部署 Ruby Web 应用程序”,它是否替代了 Mongrel?它是否像 Capistrano 一样部署 Web 应用程序?

考虑到我想测试 SSL,并且我相信 mongrel 并不支持它,那么最佳的开发服务器设置是什么?

谢谢


3
你看过Phusion Passenger的演示视频吗?它大致描述了在5分钟内将你的Rails应用程序上线所需的所有步骤。 - Hongli
29
这个无建设性的问题确实得到了很多赞,回答也是如此。 - Teemu Leisti
35
我知道这个问题违反了SO的规定,但是如果很多用户发现这个问题有用,也许是时候修改一些规定了? - Hardik
1个回答

1290

根据上下文,单词"deployment"有两个意思。您还将Apache / Nginx的角色与其他组件的角色混淆了。

历史注释:本文最初撰写于2010年11月6日,当时Ruby应用程序服务器生态系统有限。我已在2013年3月15日更新了本文,包括生态系统中的所有最新更新。

免责声明:我是Phusion Passenger的作者之一,其中一个应用程序服务器。

Apache vs Nginx

它们都是Web服务器。它们可以提供静态文件,但是 - 使用正确的模块 - 也可以提供动态Web应用程序,例如用PHP编写的应用程序。 Apache更受欢迎并具有更多功能,Nginx更小,更快,并且功能较少。

Apache和Nginx都无法直接提供Ruby Web应用程序,为此,您需要将Apache / Nginx与某种附加组件结合使用,稍后将进行描述。

Apache和Nginx还可以充当反向代理,这意味着它们可以接收传入的HTTP请求并将其转发到另一个也支持HTTP的服务器。当该服务器用HTTP响应时,Apache / Nginx将将响应转发回客户端;稍后您将了解到为什么这很重要。

Mongrel和其他生产应用程序服务器与WEBrick

Mongrel是一种Ruby“应用程序服务器”:具体来说,这意味着Mongrel是一个应用程序,它:

  1. 将您的Ruby应用程序加载到其自己的进程空间中。
  2. 设置TCP套接字,允许它与外界(例如互联网)通信。Mongrel在此套接字上侦听HTTP请求,并将请求数据传递给Ruby Web应用程序。
  3. Ruby Web应用程序随后返回一个对象,该对象描述了HTTP响应的样子,Mongrel负责将其转换为实际的HTTP响应(即实际的字节),并通过套接字发送回去。

然而,Mongrel相当过时,现在已经不再维护。更新的替代应用服务器包括:

  • Phusion Passenger
  • Unicorn
  • Thin
  • Puma
  • Trinidad(仅适用于JRuby)
  • TorqueBox(仅适用于JRuby)

稍后我会介绍它们并描述它们彼此之间以及与Mongrel的区别。

WEBrick与Mongrel执行相同的操作,但它们的区别在于:

  • WEBrick不适合生产环境,与我之前提到的所有内容都不同。WEBrick完全是用Ruby编写的。Mongrel(以及大多数其他Ruby应用程序服务器)部分由Ruby和部分由C(大多数为Ruby)组成,但其HTTP解析器是用C编写的以提高性能。
  • WEBrick较慢且不够健壮。它有一些已知的内存泄漏和已知的HTTP解析问题。
  • WEBrick通常仅在开发期间作为默认服务器使用,因为WEBrick默认包含在Ruby中。Mongrel和其他应用程序服务器需要单独安装。尽管出于某种原因Heroku选择了WEBrick作为其默认服务器,但不建议在生产环境中使用WEBrick。他们之前使用的是Thin,所以我不知道他们为什么要改用WEBrick。

应用程序服务器和世界

所有当前的Ruby应用程序服务器都支持HTTP,但某些应用程序服务器可能会直接暴露在端口80上的互联网上,而其他应用程序服务器则可能没有。

  • 可以直接暴露在互联网上的应用程序服务器:Phusion Passenger、Rainbows
  • 可能不能直接暴露在互联网上的应用程序服务器:Mongrel、Unicorn、Thin、Puma。这些应用程序服务器必须放在像Apache和Nginx这样的反向代理Web服务器后面。
  • 我不了解Trinidad和TorqueBox,所以我省略了它们。

为什么有些应用程序服务器必须放在反向代理后面?

  • 一些应用服务器每个进程只能处理一个请求。如果您想同时处理2个请求,则需要运行多个应用服务器实例,每个实例都提供相同的Ruby应用程序。这组应用服务器进程称为应用服务器集群(因此有Mongrel Cluster、Thin Cluster等名称)。然后必须设置Apache或Nginx以反向代理到此集群。 Apache / Nginx将负责在集群中分配请求(有关详细信息,请参见"I / O并发模型"部分)。
  • Web服务器可以缓冲请求和响应,保护应用程序服务器免受“慢客户端”的影响-HTTP客户端发送或接受数据速度不快的情况。您不希望应用程序服务器在等待客户端发送完整请求或接收完整响应时无所事事,因为在那段时间内应用程序服务器可能无法做任何其他事情。 Apache和Nginx非常擅长同时执行许多任务,因为它们是多线程或事件驱动的。
  • 大多数应用服务器可以提供静态文件服务,但效率不高。 Apache和Nginx可以更快地完成此任务。
  • 人们通常设置Apache / Nginx直接提供静态文件,但将与静态文件不对应的请求转发到应用服务器,这是良好的安全实践。 Apache和Nginx非常成熟,可以保护应用程序服务器免受(可能是恶意的)损坏请求的影响。

为什么有些应用服务器可以直接暴露在互联网上?

  • Phusion Passenger是与所有其他应用服务器非常不同的一种东西。其独特之处在于它可以集成到Web服务器中。
  • Rainbows的作者公开表示,直接将其暴露在互联网上是安全的。作者相当确定HTTP解析器(以及类似的东西)没有漏洞。尽管如此,作者不提供任何保证,并表示使用风险由自己承担。

应用服务器比较

在本节中,我将比较我提到的大多数应用服务器,但不包括Phusion Passenger。Phusion Passenger与其他应用服务器非常不同,因此我给它单独分了一节。我还省略了Trinidad和TorqueBox,因为我对它们不够了解,而且只有在使用JRuby时才相关。

  • Mongrel非常简单。正如前面提到的,Mongrel完全是单线程多进程的,因此只在集群中有用。没有进程监控:如果集群中的某个进程崩溃(例如由于应用程序中的错误),则需要手动重新启动。人们倾向于使用外部进程监控工具,如Monit和God。
  • Unicorn是Mongrel的一个分支。它支持有限的进程监控:如果进程崩溃,则主进程会自动重启它。它可以使所有进程都监听一个共享套接字,而不是每个进程都有一个单独的套接字。这简化了反向代理配置。与Mongrel一样,它完全是单线程多进程的。
  • Thin使用事件驱动的I/O模型,利用EventMachine库。除了使用Mongrel HTTP解析器外,它与Mongrel没有任何关系。它的群集模式没有进程监控,因此您需要监视崩溃等情况。没有类似Unicorn的共享套接字,因此每个进程都监听自己的套接字。理论上,Thin的I/O模型允许高并发性,但在大多数实际情况下,Thin仅能处理1个并发请求,因此仍然需要一个群集。更多关于这种特殊属性的信息,请参见"I/O并发模型"部分。
  • Puma也是从Mongrel分支出来的,但与Unicorn不同,Puma被设计成纯粹的多线程。因此,当前没有内置的群集支持。您需要特别注意以确保可以利用多个核心(有关更多信息,请参见"I/O并发模型"部分)。
  • Rainbows通过使用不同的库支持多个并发模型。

Phusion Passenger

Phusion Passenger的工作方式与其他应用程序服务器不同。Phusion Passenger直接集成到Apache或Nginx中,因此可以与Apache的mod_php进行比较。就像mod_php允许Apache轻松地提供PHP应用程序一样,Phusion Passenger也几乎以神奇的方式使Apache(以及Nginx!)能够提供Ruby应用程序。 Phusion Passenger的目标是尽可能少地麻烦,使一切都可以正常工作。

与为您的应用程序启动进程或群集,然后配置Apache / Nginx以提供静态文件和/或反向代理请求到进程/群集不同,使用Phusion Passenger只需要:

  1. 编辑Web服务器配置文件,并指定Ruby应用程序“public”目录的位置。
  2. 没有第二步。

所有配置都在Web服务器配置文件中完成。Phusion Passenger自动化了几乎所有内容。无需启动群集和管理进程。相对于其他应用程序服务器,Phusion Passenger的移动部件要少得多。这种易用性是人们使用Phusion Passenger的主要原因之一。

与其他应用程序服务器不同的是,Phusion Passenger主要由C ++编写,因此非常快。

还有一个Enterprise variant的Phusion Passenger,具有更多功能,例如自动滚动重启、多线程支持、部署错误抵抗等。

由于上述原因,Phusion Passenger是目前最受欢迎的Ruby应用程序服务器,支持超过150,000个网站,包括像纽约时报、皮克斯、Airbnb这样的大型网站。
Phusion Passenger相对于其他应用程序服务器提供了更多功能和优势,例如:
- 根据流量动态调整进程数量。我们在资源受限的服务器上运行大量Rails应用程序,这些应用程序不面向公众,在我们组织中的人每天最多只使用几次,例如Gitlab、Redmine等。Phusion Passenger可以在它们不使用时关闭这些进程,当需要使用时再启动它们,从而为更重要的应用程序提供更多资源。而其他应用程序服务器则会一直开着所有进程。 - 有些应用程序服务器根据设计并不擅长处理某些工作负载。例如,Unicorn仅适用于快速运行的请求:请参见Unicorn网站部分“Just Worse in Some Cases”。 Unicorn不擅长的工作负载包括:
- 流式工作负载(例如Rails 4实时流或Rails 4模板流)。 - 应用程序执行HTTP API调用的工作负载。 Phusion Passenger Enterprise 4或更高版本的混合I/O模型使其成为这些类型工作负载的最佳选择。
  • 其他应用服务器要求用户至少运行一个实例才能运行一个应用程序。相比之下,Phusion Passenger支持在单个实例中运行多个应用程序。这极大地减少了管理开销。
  • 自动用户切换是一项方便的安全功能。
  • Phusion Passenger支持许多MRI Ruby,JRuby和Rubinius。Mongrel,Unicorn和Thin仅支持MRI。Puma也支持所有三种。
  • Phusion Passenger实际上不仅支持Ruby!它还支持Python WSGI,因此它可以运行Django和Flask应用程序。实际上,Phusion Passenger正在朝着成为多语言服务器的方向发展。Node.js支持在待办事项列表中。
  • 带外垃圾收集。Phusion Passenger可以在正常请求/响应周期之外运行Ruby垃圾收集器,从而可能将请求时间缩短数百毫秒。Unicorn也有类似的功能,但Phusion Passenger的版本更加灵活,因为 1)它不仅限于GC,还可以用于任意工作。 2)Phusion Passenger的版本适用于多线程应用程序,而Unicorn的版本则不适用。
  • 自动滚动重启。在Unicorn和其他服务器上进行滚动重启需要进行一些脚本编写工作。Phusion Passenger Enterprise完全自动化了这个过程。

还有更多的功能和优势,但列表实在太长了。您应该参考综合的Phusion Passenger手册(Apache版本, Nginx版本)或Phusion Passenger网站获取信息。

I/O并发模型

  • 单线程多进程。 传统上,这是Ruby应用服务器中最流行的I/O模型之一,部分原因是Ruby生态系统中的多线程支持非常糟糕。每个进程一次只能处理一个请求。Web服务器在进程之间进行负载均衡。该模型非常强大,并且程序员很少有机会引入并发错误。但是,它的I/O并发性极其有限(受进程数量限制)。该模型非常适合快速、短时间运行的工作负载。但是,对于慢速、长时间运行的阻塞I/O工作负载(例如涉及调用HTTP API的工作负载)非常不适用。
  • 纯多线程。 现在,Ruby生态系统具有出色的多线程支持,因此这种I/O模型变得非常可行。多线程允许高I/O并发性,使其适用于短时间和长时间的阻塞I/O工作负载。程序员更有可能引入并发错误,但幸运的是,大多数Web框架都是设计成这样的方式,以使这种情况仍然非常不可能发生。但需要注意的是,MRI Ruby解释器即使有多个线程,也不能利用多个CPU核心,因为使用了全局解释器锁(GIL)。您可以通过使用多个多线程进程来解决这个问题,因为每个进程都可以利用一个CPU核心。JRuby和Rubinius没有GIL,因此它们可以在单个进程中充分利用多个核心。
  • 混合多线程多进程。 主要由Phusion Passenger Enterprise 4及更高版本实现。您可以轻松地在单线程多进程、纯多线程或甚至每个进程具有多个线程之间进行切换。该模型集两种模型的优点于一身。
  • 事件驱动。 这种模型与先前提到的模型完全不同。它允许非常高的I/O并发性,因此非常适用于长时间的阻塞I/O工作负载。为了利用它,需要应用程序和框架的明确支持。然而,所有主要的框架如Rails和Sinatra都不支持事件驱动的代码。这就是为什么在实践中,Thin进程仍然无法处理多个请求,使其实际上表现与单线程多进程模型相同。有一些专门的框架可以利用事件驱动I/O,例如Cramp。
最近在Phusion博客上发布了一篇关于如何优化进程和线程数量的文章,以适应你的工作负载。请参见Tuning Phusion Passenger's concurrency settings
Capistrano是完全不同的东西。在所有前面的部分中,“部署”指的是启动Ruby应用程序在应用服务器中,使其对访问者可用,但在此之前通常需要做一些准备工作,例如:
- 将Ruby应用程序的代码和文件上传到服务器机器。 - 安装应用程序所依赖的库。 - 设置或迁移数据库。 - 启动和停止应用程序可能依赖的任何守护程序,例如Sidekiq/Resque工作者或其他内容。 - 在设置应用程序时需要完成的任何其他事情。
在Capistrano的上下文中,“部署”是指执行所有这些准备工作。Capistrano不是一个应用服务器。相反,它是一个自动化所有这些准备工作的工具。您告诉Capistrano您的服务器在哪里以及每次部署新版本的应用程序时需要运行哪些命令,Capistrano将为您上传Rails应用程序到服务器并运行您指定的命令。
Capistrano始终与应用程序服务器结合使用。它不会替换应用程序服务器。反之,应用程序服务器也不能替换Capistrano,它们可以与Capistrano结合使用。
当然,您不必使用Capistrano。如果您更喜欢通过FTP上传您的Ruby应用程序,并手动运行相同的命令步骤,则可以这样做。其他人已经厌倦了这种方式,所以他们使用Capistrano自动化了这些步骤。

79
你应该在某个地方发布这个。现在很容易,但当我刚开始使用 Rails 时,很难获取任何有用的信息。 - spegoraro
10
非常好的文章!对我来说也解决了很多问题。你可以添加一些其他元素,比如Bundler和RVM,并将其制作成一篇有影响力的博客文章! :) - Damien Roche
40
需要将其包含在Rails指南中。 - Dorian
38
@Hongli 这篇文章对Phusion Passenger非常有利。也许为了客观起见,将您与该项目的关联(CTO,http://www.phusion.nl/about)加入其中会更明智? - Bert Goethals
7
迄今为止我在SO上看到的最佳答案! - MadOgre
显示剩余20条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接