Ruby on Rails服务器选项

为Ruby on Rails应用程序设置开发服务器的整个问题让我很困惑。还有WEBrick, Mongrel, Passenger, Apache, Nginx等等,我不太明白它们所扮演的不同角色。

我开始使用WEBrick,现在我使用Mongrel进行开发。这些服务器是独立的,还是位于Apache的前面?

我读过Passenger,但我不太明白它是什么,网站上说“使Ruby web应用程序的部署变得轻而易举”,它会取代Mongrel吗?它是否像同样部署web应用程序的Capistrano ?

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

谢谢

95194 次浏览

根据上下文,“部署”一词可能有两种含义。你也混淆了Apache/Nginx的角色和其他组件的角色。

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

免责声明:我是Phusion Passenger(应用服务器之一)的作者之一。

Apache vs Nginx

它们都是网络服务器。它们可以提供静态文件,但是-使用正确的模块-也可以提供动态web应用程序,例如那些用PHP编写的应用程序。Apache更流行,有更多的功能,Nginx更小,更快,功能更少。

Apache和Nginx都不能开箱即用地提供Ruby web应用,要做到这一点,你需要结合使用Apache/Nginx和某种附加组件,后面会介绍。

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

Mongrel和其他生产应用服务器vs WEBrick

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

  1. 将Ruby应用程序加载到它自己的进程空间中。
  2. 设置一个TCP套接字,允许它与外部世界(例如Internet)通信。 Mongrel监听这个套接字上的HTTP请求,并将请求数据传递给Ruby web应用程序
  3. Ruby web应用程序然后返回一个对象,该对象描述了HTTP响应应该是什么样子,Mongrel负责将其转换为实际的HTTP响应(实际的字节)并通过套接字发回。

然而,Mongrel是相当过时的,现在它不再维持。更新的应用服务器有:

  • Phusion乘客
  • 独角兽
  • 彪马
  • 特立尼达(仅JRuby)
  • TorqueBox(仅限JRuby)

我将在后面介绍它们,并描述它们彼此之间以及与Mongrel之间的区别。

WEBrick做的事情和Mongrel一样,但区别是:

  • WEBrick不适合生产,不像我前面提到的其他东西。WEBrick完全是用Ruby编写的。Mongrel(和大多数其他Ruby应用服务器)是部分Ruby和部分C语言(主要是Ruby),但它的HTTP解析器是用C语言编写的,以提高性能。
  • WEBrick速度较慢,健壮性较差。它有一些已知的内存泄漏和一些已知的HTTP解析问题。
  • 在开发过程中,WEBrick通常只作为默认服务器使用,因为默认情况下,WEBrick包含在Ruby中。Mongrel和其他应用服务器需要单独安装。不建议在生产环境中使用WEBrick,尽管出于某种原因Heroku选择WEBrick作为默认服务器。他们以前使用Thin,所以我不知道为什么他们切换到WEBrick。

应用服务器和整个世界

目前所有的Ruby应用服务器都使用HTTP,但是一些应用服务器可能直接在端口80上公开给Internet,而其他的则可能不是。

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

为什么某些应用服务器必须置于反向代理之后?

  • 有些应用服务器每个进程只能同时处理1个请求。如果你想同时处理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服务器中。
  • 《彩虹》的作者公开表示,直接把它暴露在互联网上是安全的。作者相当肯定HTTP解析器中没有漏洞(以及类似的漏洞)。不过,作者不提供任何保证,并表示使用风险自负。

应用服务器比较

在本节中,我将比较我提到的大多数应用服务器,但不包括Phusion Passenger。Phusion Passenger是如此不同于其他的野兽,我给了它一个专门的部分。我还省略了Trinidad和TorqueBox,因为我对它们不够了解,但它们只在使用JRuby时才有用。

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

Phusion乘客

Phusion乘客的工作方式与其他的非常不同。Phusion Passenger直接集成到Apache或Nginx中,因此可以与Apache的mod_php进行比较。就像mod_php允许Apache为PHP应用服务一样,Phusion Passenger允许Apache(以及Nginx!)几乎神奇地为Ruby应用服务。Phusion Passenger的目标是尽可能少地麻烦地让一切Just Work(tm)。

而不是为你的应用程序启动一个进程或集群,并配置Apache/Nginx提供静态文件和/或反向代理请求到进程/集群与Phusion Passenger,你只需要:

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

所有配置都在web服务器配置文件中完成。Phusion Passenger几乎实现了一切自动化。不需要启动集群并管理进程。启动/停止进程,当它们崩溃时重新启动它们,等等——所有这些都是自动化的。与其他应用服务器相比,Phusion Passenger的活动部件要少得多。这种易用性是人们使用Phusion Passenger的主要原因之一。

与其他应用服务器不同的是,Phusion Passenger主要是用c++编写的,这使得它非常快。

Phusion Passenger还有一个企业变体版本,它有更多的特性,比如自动滚动重启、多线程支持、防部署错误等等。

由于上述原因,Phusion Passenger是目前最受欢迎的Ruby应用服务器,支持超过15万个网站,包括纽约时报、皮克斯、Airbnb等大型网站。

Phusion Passenger vs其他应用服务器

Phusion Passenger提供了更多的功能,并提供了许多优于其他应用服务器的优势,例如:

  • 根据流量动态调整进程数。我们在资源有限的服务器上运行大量不面向公众的Rails应用程序,我们组织中的人员每天最多只使用几次。比如Gitlab, Redmine等等。Phusion Passenger可以在不使用这些进程时将它们旋转下来,在使用时将它们旋转起来,允许更多的资源用于更重要的应用程序。在其他应用服务器上,你的所有进程都是一直开启的。
  • 有些应用服务器在设计上并不擅长某些工作负载。例如,Unicorn仅为快速运行的请求而设计:参见独角兽网站部分“在某些情况下更糟糕”。

Unicorn不擅长的工作量有:

  • 流工作负载(例如Rails 4实时流或Rails 4模板流)。
  • 应用程序执行HTTP API调用的工作负载。

Phusion客运企业或更高版本中的混合I/O模型使它成为这类工作负载的绝佳选择。

  • 其他应用程序服务器要求用户每个应用程序至少运行一个实例。相比之下,Phusion Passenger在单个实例中支持多个应用程序。这大大降低了管理开销。
  • 用户自动切换,方便安全功能。
  • Phusion Passenger支持多种MRI Ruby、JRuby和Rubinius。Mongrel, Unicorn和Thin只支持MRI。Puma也支持这3种。
  • 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客运企业完全自动化这种方式为您。

还有更多的特点和优势,但清单真的很长。你应该参考全面的Phusion乘客手册(Apache版本Nginx版本)或Phusion Passenger网站获取信息。

I/O并发模型

  • 单线程的多进程。这是传统上Ruby应用服务器最流行的I/O模型,部分原因是Ruby生态系统中的多线程支持非常糟糕。每个进程一次只能处理1个请求。web服务器在进程之间实现负载平衡。这个模型非常健壮,程序员几乎没有机会引入并发性错误。但是,它的I/O并发性非常有限(受进程数量的限制)。此模型非常适合快速、短时间运行的工作负载。它非常不适合缓慢、长时间运行的阻塞I/O工作负载,例如涉及调用HTTP api的工作负载。
  • 现在Ruby生态系统拥有出色的多线程支持,因此这种I/O模型已经变得非常可行。多线程允许高I/O并发性,使其适用于短时间运行和长时间运行的阻塞I/O工作负载。程序员更有可能引入并发错误,但幸运的是,大多数web框架都是按照这样的方式设计的,这仍然是非常不可能的。但是需要注意的一点是,由于使用了全局解释器锁(GIL), MRI Ruby解释器即使有多个线程也不能利用多个CPU内核。您可以通过使用多个多线程进程来解决这个问题,因为每个进程都可以利用一个CPU内核。JRuby和Rubinius没有GIL,所以它们可以在一个进程中充分利用多个核。
  • 混合多线程多进程。主要由Phusion客运企业4及后续版本实现。您可以轻松地在单线程多进程、纯多线程、甚至多个进程之间切换,每个进程都有多个线程。这种模式是两全其美的。
  • 这个模型与前面提到的模型完全不同。它允许非常高的I/O并发性,因此非常适合长时间运行的阻塞I/O工作负载。要利用它,需要应用程序和框架的显式支持。然而,所有主要的框架,如Rails和Sinatra都不支持事件代码。这就是为什么在实践中Thin进程仍然不能同时处理多个请求的原因,这使得它的行为与单线程多进程模型相同。有一些专门的框架可以利用事件I/O,比如Cramp。

Phusion博客上最近发布了一篇文章,内容是在给定工作负载的情况下优化进程和线程的数量。看到# EYZ0。

Capistrano

卡皮斯特拉诺则完全不同。在前面的所有章节中,“部署”指的是在应用服务器上启动Ruby应用程序,以便访问者可以访问它,但在这之前通常需要做一些准备工作,例如:

  • 将Ruby应用程序的代码和文件上传到服务器机器。
  • 安装应用程序所依赖的库。
  • 设置或迁移数据库。
  • 启动和停止应用程序可能依赖的任何守护进程,如Sidekiq/Resque worker或其他。
  • 设置应用程序时需要做的其他事情。

在Capistrano的上下文中,“部署”指的是做所有这些准备工作。Capistrano不是应用服务器。相反,它是一个自动化所有准备工作的工具。每次部署新版本的应用程序时,您告诉Capistrano服务器的位置以及需要运行哪些命令,Capistrano将负责为您将Rails应用程序上传到服务器并运行您指定的命令。

Capistrano总是与应用程序服务器结合使用。它不替换应用服务器。反之亦然,应用服务器不能取代Capistrano,它们可以与Capistrano结合使用。

当然你不使用Capistrano。如果您更喜欢使用FTP上传Ruby应用程序,并且每次手动运行相同步骤的命令,那么您可以这样做。其他人厌倦了,所以他们在Capistrano自动化了这些步骤。