翻译 Ruby 服务器对比

besfan · 2015年04月23日 · 最后由 franklinyu 回复于 2015年09月15日 · 16420 次阅读
本帖已被管理员设置为精华贴

     之前一直对 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 已经不再维护了,其他替代的服务器是:

  • Phusion Passenger
  • Unicorn
  • Thin
  • Puma
  • Trinidad (JRuby only)
  • TorqueBox (JRuby only)

     接下来我会讲一讲他们和 Mongrel 的区别

     WEBrick 和 Mongrel 很像,区别如下:

  • WEBrick 不适合用于 production。WEBrick 完全是用 Ruby 写的;Mongrel(以及其他 Ruby 应用服务器)是部分 Ruby 部分 C,主要是 Ruby,但它的 HTTP 解析器为了性能是用 C 写的。
  • WEBrick 速度比较慢而且不够强壮,有普遍知道的内存泄漏问题,以及 HTTP 解析问题。
  • 因为 WEBrick 是 Ruby 默认自带的,所以 WEBrick 经常用于 development 环境下作为默认服务器,而其他的服务器则需要另外安装。不建议在 production 环境下使用 WEBrick 服务器,虽然因为某些原因,Heroku 选择了 WEBrick 作为默认服务器,他们以前使用的是 Thin,但我不知道他们为什么换到了 WEBrick。

三,应用服务器世界

     当前所有的 Ruby 应用服务器都是 HTTP 类型的,一些服务器直接将 80 端口暴露到 Internet 中,另一些则没有。

  • 暴露 80 端口的:Phusion Passenger,Rainbows。
  • 没有直接暴露的:Mongrel, Unicorn, Thin, Puma。这些服务器必须必须置于反向代理服务器之后,比如 Apache 和 Nginx。
  • 我不了解 Trinidad 和 TorqueBox,所以就忽略了。

为什么有些服务器需要置于反向代理之后?

  • 某些服务器的每个进程在同一时间只能处理一个请求,如果想同时处理两个请求,你就需要启动多个服务器实例,都伺服同一个 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 和其他应用服务器不一样,其中一个特点是可以融入其他服务器。
  • Rainbows 的作者公开指出,Rainbows 可以直接暴露在 Internet 中。他非常确认在解析 HTTP 过程中不会轻易遭受攻击。当然,作者也并不做任何担保,并表示不同应用环境下有其相应的风险。

四,应用服务器对比

     在这一章中,我会比较我提过的大多数服务器,但不包括 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 配置静态目录,或者设置反向代理。

     你只需要:

  1. 编辑 web 服务器的配置文件,写入 Ruby 应用下 public 文件夹的路径
  2. 没有第二步。

     所有的配置工作都在 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 提供了更多的特性功能:

  • 根据访问量自动调整进程的数量。在资源有限的服务器上,我们运行多个 Ruby 应用,而我们的应用不对外公开,而且组织内的访客每天的访问量也很低,例如 Gitlab, Redmine 等。Phusion Passenger 能够在进程不使用的时候挂起他们,需要的时候恢复进程,为更重要的应用腾出资源。相比之下,其他的服务器的所有进程会一直运行着。
  • 有些服务器不适合某些特定的负荷。例如 Unicorn 为轻量快速的请求而设计,See  the Unicorn website section "Just Worse in Some Cases".

          Unicorn 不擅长的负荷:

               > 流(e.g. Rails 4 live streaming or Rails 4 template streaming)

               > 调用 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 的支持已经列在计划中。
  • Out-of-band garbage collection。Phusion Passenger 可以在请求的循坏外执行 Ruby 的垃圾回收,可以潜在地减少几百毫秒的请求时间(reducing request times by hundreds of milliseconds)。Unicorn 也有类似的功能,但是 Phusion Passenger 的版本更加灵活,因为 1,it's not limited to GC and can be used for arbitrary work。2,Phusion Passenger 的版本适应多进程应用,而 Unicorn 则不行。
  • 自动回滚重启(Automated rolling restarts)。Unicorn 以及其他应用服务器的回滚重启需要脚本来执行,Phusion Passenger 企业版自动帮你完成了。

     还有更多的特性和优势,暂不一一列举。你可以参考全面的 Phusion Passenger 手册 ( Apache versionNginx 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 应用,然后对访客开放,但是在这之前需要一些准备工作,例如:

  • 将 Ruby 应用的代码和文件上传到服务器机器上。
  • 安装应用所依赖的库。
  • 创建或者迁移数据库。
  • 启动或者停止应用依赖的守护进程,例如 Sidekiq/Resque  或者 whatever。
  • 启动应用时需要做的所有其他事情。 

     在 Capistrano 的语义中,“部署”意味着去做所有的准备工作。Capistrano 不是一个服务器,反而是一个自动做那些准备工作的工具。你告诉 Capistrano 你的服务器在哪里,以及每当你部署新版本应用的时候需要执行的命令,Capistrano 就能帮你上传 Ruby 应用到服务器上并且运行你指定的命令。

     Capistrano 总是与应用服务器组合使用,并不会替代应用服务器。反之亦然,应用服务器也不会替代 Capistrano。

     当然 Capistrano 也不是必须使用的。如果你可以使用 FTP 或者 手动上传 Ruby 应用,每一次都执行相同的动作。其他人厌倦这种重复,所以他们在 Capistrano 中自动执行这些步骤。

out-of-the-box:开箱即用,意思是只需很少量的准备工作就可以干活了,也可引申为“很好的,很适用的……”

这篇文章是 Phusion Passenger 的人写的,我当初看完后也选择了 Passenger .

https://www.phusionpassenger.com/documentation_and_support

Puma 也是从 Mongrel 中fork出来的,但和 Unicorn 不一样的是,Puma 被设计成多进程的。目前不支持集群。你需要特别确认的是你能实现多核 这段翻译地有点大意 Puma 是基于多线程,使用 Thread Pool 实现。因为 GIL 的存在,所以 MRI 不能利用多核实现 CPU 并行,所以你需要特别确认的是你能利用多核。

@nightire @yanguango 感谢指正,已修改

「Neither Apache nor Nginx can serve Ruby web apps out-of-the-box」 「让 Apache 和 Nginx 来伺服 Ruby 服务器都是开箱即用(out-of-the-box)的」

貌似意思反了,应该是「都不是开箱即用的」

反正一直是 passenger,方便……

最早用的 passenger,中间用了 thin/puma/rainbows,意在提高并发,但 Ruby 多线程并发并不可靠,整体性能和可靠性还不如 passenger 开线程安全模式。

改用 passenger 了,感觉很省事

现在流行的基本上是 heroku 那套了吧。

这个要收藏咯

有的小脚本程序我就用 WEBrick 来跑 sinatra...接收来自主服务器的操作。。挺稳定的。。

如果有 phusion passenger 5 (raptor) vs unicorn 的性能测试我就点赞

这个帖子 收藏了 谢谢楼的分享!

#15 楼 @hbin 嗯,rails 支持多线程安全之后,Puma 和 rainbows 这种多线程的服务器必然越来越得势。 Passenger 以前常用,后来就不太用了。主要是 nginx 会经常需要升级,如果同时需要每次再编译甚至升级 passenger 总感觉比较麻烦。 Nginx+Puma/Rainbows/Unicorn 长期运维省事一些。

Heroku 选择了 WEBrick 作为默认服务器 据我所知 Heroku 换成了 Unicorn

passenger 牛逼的功能都是企业版提供的呀..

"still, the author provides no warranty and says that usage is at own risk." 这一句应该可以翻译为:“当然,作者也并不做任何担保,并表示不同应用环境下有其相应的风险。”

"Bare bone" 翻译成暴露的石头?裸露的骨头还可以原谅,可以翻译成“只有最基础的功能”。

22 楼 已删除

#17 楼 @tuliang 據我所知,Heroku 換成了 Puma(見 #15 楼

chenyunli [该话题已被删除] 提及了此话题。 10月18日 16:36
需要 登录 后方可回复, 如果你还没有账号请 注册新账号