小编典典

Ruby on Rails 服务器选项

all

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

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

我读过有关Passenger的文章,但我不太明白它是什么,该网站说“使Ruby Web应用程序的部署变得轻而易举”,它是否取代了Mongrel?是不是也像
Capistrano 一样部署 Web 应用程序?

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

谢谢


阅读 167

收藏
2022-03-06

共1个答案

小编典典

根据上下文,“部署”一词可以有两种含义。您还将 Apache/Nginx 的角色与其他组件的角色混淆了。

历史记录:本文最初写于 2010 年 11 月 6 日,当时 Ruby 应用服务器生态系统受到限制。我已于 2013 年 3 月 15
日更新了这篇文章,其中包含生态系统中的所有最新更新。

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

阿帕奇与 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 套接字,允许它与外部世界(例如 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 服务器中。
  • Rainbows的作者公开表示直接将其暴露在互联网上是安全的。作者相当肯定 HTTP 解析器(和类似的)没有漏洞。尽管如此,作者不提供任何保证,并表示使用风险自负。

应用服务器比较

在本节中,我将比较我提到的大多数应用程序服务器,但不比较 Phusion Passenger。Phusion Passenger
与其他野兽是如此不同,我已经给它一个专门的部分。我也省略了 Trinidad 和 TorqueBox,因为我不太了解它们,但它们只有在使用 JRuby
时才有意义。

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

Phusion乘客

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 应用程序的“公共”目录的位置。
  2. 没有第 2 步。

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

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

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

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

Phusion Passenger 与其他应用服务器

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

  • 根据流量动态调整进程数。我们在资源受限的服务器上运行了大量不面向公众的 Rails 应用程序,而且我们组织中的人每天最多只使用几次。诸如 Gitlab、Redmine 等之类的东西。Phusion Passenger 可以在不使用时关闭这些进程,并在使用时启动它们,从而为更重要的应用程序提供更多资源。使用其他应用服务器,您的所有进程始终处于打开状态。
  • 根据设计,某些应用服务器不擅长某些工作负载。例如,Unicorn 仅适用于快速运行的请求:请参阅Unicorn 网站部分“在某些情况下更糟”。

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 也支持所有 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 Passenger Enterprise 为您完全自动化了这种方式。

还有更多的功能和优势,但列表真的很长。您应该参考全面的 Phusion Passenger 手册(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 Passenger Enterprise 4 及更高版本实现。您可以轻松地在单线程多进程、纯多线程或什至每个具有多个线程的多个进程之间切换。该模型提供了两全其美的效果。
  • 发生。 该模型与前面提到的模型完全不同。它允许非常高的 I/O 并发,因此非常适合长时间运行的阻塞 I/O 工作负载。要使用它,需要应用程序和框架的明确支持。然而,像 Rails 和 Sinatra 这样的所有主要框架都不支持事件代码。这就是为什么在实践中瘦进程仍然不能一次处理超过 1 个请求,使其有效地表现与单线程多进程模型相同。有一些专门的框架可以利用事件 I/O,例如 Cramp。

最近在 Phusion 博客上发布了一篇关于根据您的工作负载优化调整进程和线程数量的文章。请参阅调整 Phusion Passenger
的并发设置

卡皮斯特拉诺

Capistrano 是完全不同的东西。在前面的所有部分中,“部署”是指在应用程序服务器中启动 Ruby
应用程序的行为,以便访问者可以访问它,但在此之前,通常需要做一些准备工作,例如:

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

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

Capistrano 始终与应用程序服务器结合使用。它不会取代应用程序服务器。反之亦然,应用服务器不会取代 Capistrano,它们可以与
Capistrano 结合使用。

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

2022-03-06