之前一直对 Ruby 的服务器不是很了解,在 stackoverflow 看到一篇文章感觉不错,顺便翻译了一下,英语不好,如果哪里错了请大家指出,避免误导他人。 原文地址:http://stackoverflow.com/questions/4113299/ruby-on-rails-server-options
The word "deployment" can have two meanings depending on the context. You are also confusing the roles of Apache/Nginx with the roles of other components.
Historic note: This article was originally written on November 6, 2010, when the Ruby app server ecosystem was limited. I've updated this article on March 15 2013 with all the latest updates in the ecosystem.
Disclaimer: I am one of the authors of Phusion Passenger, one of the app servers.
一,Apache vs Nginx
他们都是 web 服务器,都能伺服静态文件,利用恰当的模块也能伺服动态的 web 应用。Apache 更加流行,拥有更多的功能;Nginx 则相对小巧、快速、功能少。
让 Apache 和 Nginx 来伺服 Ruby 服务器都不是开箱即用(out-of-the-box)的,为此你需要使用另外的插件来组合他们。
Apache 和 Nginx 都能作为反向代理,就是说他们能够把进来的 HTTP 请求发给其他服务器,接着把该服务器的 HTTP 响应转给客户端,后面会看到为什么和这个有关系。
二,Mongrel 以及其他 production 环境的服务器 vs WEBrick
Mongrel 是 Ruby 实现的应用服务器,具体来说:
1,在自己的进程空间中加载 Ruby 应用。
2,创建一个 TCP socket,允许它可以和外部世界通信 (例如 Internet)。Mongrel 在这个 socket 上监听 HTTP 请求,并把请求数据转发给 Ruby 应用。
3,Ruby 应用返回一个描述 HTTP 响应的对象,Mongrel 将其转换为真正的 HTTP 响应字节,并发回到 socket 中。
然而 Mongrel 已经不再维护了,其他替代的服务器是:
接下来我会讲一讲他们和 Mongrel 的区别
WEBrick 和 Mongrel 很像,区别如下:
三,应用服务器世界
当前所有的 Ruby 应用服务器都是 HTTP 类型的,一些服务器直接将 80 端口暴露到 Internet 中,另一些则没有。
为什么有些服务器需要置于反向代理之后?
某些服务器的每个进程在同一时间只能处理一个请求,如果想同时处理两个请求,你就需要启动多个服务器实例,都伺服同一个 Ruby 应用。这种应用服务器进程的集合称为应用服务器集群(比如 Mongrel Cluster, Thin Cluster)。然后你必须启动 Apache 或者 Nginx,给集群做反向代理,Apache/Nginx 会处理好集群中不同应用实例间的请求分发。(更多内容参见章节 "I/O 并发模型”)
Web 服务器可以缓存请求和响应。有些客户端发送数据、接收数据的速度缓慢,你当然不希望应用服务器在等待客户端收发数据时什么也不干,Web 服务器可以隔离应用服务器和慢客户端。Apache 和 Nginx 擅长同时很多事情,因为他们是多线程或者基于事件的。
大多数的应用服务器可以伺服静态文件,但不擅长,而 Apache 和 Nginx 可以更快速度处理这件事情。
人们经常直接使用 Apache 或者 Nginx 伺服静态文件,而不会处理需要转发的请求(forward requests),这是比较安全的策略。Apache 和 Nginx 足够聪明,可以保护应用服务器远离恶意请求。
为什么有些服务器可以直接暴露在 Internet 中?
四,应用服务器对比
在这一章中,我会比较我提过的大多数服务器,但不包括 Phusion Passenger。Phusion Passenger 和其他的不一样,我会单独开出一章。我还会忽略 Trinidad 和 TorqueBox,因为我对他们不是很了解,只有你用到 JRuby 的时候才会涉及到他们。
Mongrel 只有最基础的功能。像之前提到的,Mongrel 仅仅是单线程、多进程,所以它只用于集群(cluster)中。没有进程监控,意味着如果集群中一个进程崩溃了,则需要手动重启。人们需要使用额外的进程来照看 Mongrel,比如 Monit 和 God。
Unicorn 是从 Mongrel 中 fork 出来的。支持监控一定数量的的进程:如果一个进程崩溃了,则会被主进程自动重启。它能让所有进程都监听同一个共享的 socket,而不是每个进程使用单独的 socket,这会简化反向代理的配置。像 Mongrel 一样,Unicorn 是单线程、多进程。
Thin 利用 EventMachine 库,实现基于事件的 I/O 模型。它并不是使用 Mongrel 的 HTTP 解析器,没有基于 Mongrel。它的集群节点没有进程监控,所以你需要去监控进程是否崩溃。每个进程监听各自的 socket,不像 Unicorn 一样共享 socket。理论上来说,Thin 的 I/O 模型允许高并发,这也是 Thin 被应用的大部分场合。一个 Thin 的进程只能处理一个并发请求,所以你还需要集群。关于这个古怪的性质,更多内容参见“I/O 并发模型”。
Puma 也是从 Mongrel 中 fork 出来的,但和 Unicorn 不一样的是,Puma 是基于多线程,使用 Thread Pool 实现。因为 GIL 的存在,所以 MRI 不能利用多核实现 CPU 并行,所以你需要特别确认的是你能利用多核。更多内容参见“I/O 并发模型”。
Rainbows 通过给不同的库实现多种并发模型 。
五,Phusion Passenger
Phusion Passenger 和其他的不一样。他直接融入 Apache 或者 Nginx,类似于 Apache 的 mod_php。就像 mod_php 使 Apache 伺服 PHP 应用一样,Phusion Passenger 也可以使 Apache 或者 Nginx 伺服 Ruby 应用。Phusion Passenger 的目标是所有的事情做起来尽可能地减少麻烦。
如果使用 Phusion Passenger 的话,你不需要为你的应用启动一个进程或者集群,为 Apache/Nginx 配置静态目录,或者设置反向代理。
你只需要:
所有的配置工作都在 Web 服务器配置文件的指导下做完了,Phusion Passenger 几乎自动化了所有事情,不需要启动集群以及管理进程。启动或者停止进程,他们崩溃时重启,这些都被自动化了。和其他应用服务器相比,Phusion Passenger 所需要做的改动工作非常少,这是人们使用 Phusion Passenger 的主要原因。
和其他应用服务器不同的是,Phusion Passenger 主要是用 C++ 写的,速度很快。
Phusion Passenger 的企业版有更多的特性,比如自动回滚重启,支持多线程,容错部署。(such as automated rolling restarts, multithreading support, deployment error resistance, etc.)
基于以上原因,Phusion Passenger 是当前最流行的 Ruby 应用服务器,服务于超过 50,000 站点,包括大型站点:New York Times, Pixar, Airbnb。
六,Phusion Passenger vs 其他服务器
相对其他的服务器 ,Phusion Passenger 提供了更多的特性功能:
Unicorn 不擅长的负荷:
> 流(e.g. Rails 4 live streaming or Rails 4 template streaming)
> 调用 HTTP API
Phusion Passenger Enterprise 4及后续版本中多种 I/O 模型,使它非常适合这种负荷。
还有更多的特性和优势,暂不一一列举。你可以参考全面的 Phusion Passenger 手册 ( Apache version, Nginx version),或者到官网得到更多信息。
七,I/O 并发模型
单线程,多进程。 Ruby 应用服务器中比较常见、流行的 I/O 模型,主要是因为 Ruby 生态系统中的多线程支持比较差。一个进程同时仅且只能处理一个请求,web 服务器通过多进程来进行均衡负载。这种模型比较稳定,开发者不会轻易造成并发 bug。这种模型适合执行快速的短请求,不适合速度慢、长请求阻塞 I/O 的运算,例如 调用 HTTP API。
纯多线程 。现在 Ruby 生态系统已经很支持多线程了,所以这种 I/O 模型变得切实可行。多线程支持高 I/O 并发,既适合短请求也适合长请求。开发者也很容易引入并发 bug,幸运的是大多数框架按照这种方式设计,所以也不太可能发生。有一个需要注意的事情是,因为使用了全局解释器锁(GIL),MRI Ruby 解释器不能均衡使用多个 CPU 内核,即使有多个线程。为此,你可以使用多个进程,每个进程使用一个 CPU 内核。JRuby 和 Rubinius 没有 GIL,所以他们的一个进程可以均衡负载多个 CPU 内核。
结合多线程、多进程 。Phusion Passenger Enterprise 4 以后版本实现了。你可以轻易在以下模型切换:单进程多线程,纯多线程,多进程多线程。这种模型给出了最好的选择方式。
事件。这种模型和之前提到的模型不一样。它允许极高的 I/O 并发,以及非常适合长请求。为实现此功能,需要从应用到框架的详细支持。然而主要的框架(Rails 和 Sinatra)并不支持事件模型。这也是实际上一个 Thin 进程同时不能处理多个请求的原因,就像单线程多进程模型一样。只有专门的框架才充分利用事件 I/O 模型,例如 Cramp。
八,Capistrano
Capistrano 和其他的不一样。在之前的所有章节中,“部署”指的是在服务器上启动 Ruby 应用,然后对访客开放,但是在这之前需要一些准备工作,例如:
在 Capistrano 的语义中,“部署”意味着去做所有的准备工作。Capistrano 不是一个服务器,反而是一个自动做那些准备工作的工具。你告诉 Capistrano 你的服务器在哪里,以及每当你部署新版本应用的时候需要执行的命令,Capistrano 就能帮你上传 Ruby 应用到服务器上并且运行你指定的命令。
Capistrano 总是与应用服务器组合使用,并不会替代应用服务器。反之亦然,应用服务器也不会替代 Capistrano。
当然 Capistrano 也不是必须使用的。如果你可以使用 FTP 或者 手动上传 Ruby 应用,每一次都执行相同的动作。其他人厌倦这种重复,所以他们在 Capistrano 中自动执行这些步骤。