为什么 Unicorn 需要与 Nginx 一起部署?

我想知道 Nginx 和独角兽之间的区别。据我所知,Nginx 是一个 Web 服务器,而 Unicorn 是一个 Ruby HTTP 服务器。

既然 Nginx 和 Unicorn 都可以处理 HTTP 请求,那么在 RoR 应用程序中使用 Nginx 和 Unicorn 的组合有什么必要呢?

36091 次浏览

Nginx 可以用来为独角兽服务器上的慢客户端提供服务,因为慢客户端会阻塞独角兽服务器。Nginx 被用作某种代理缓冲所有请求和响应到缓慢的客户端。

参见 http://unicorn.bogomips.org/

Nginx
enter image description here
独角兽
enter image description here
有关详细信息,请参阅 独角兽在 Github

Nginx 是一个纯 Web 服务器,用于向另一个套接字提供 静态内容和/或 重定向请求以处理请求。

独角兽是一个 机架网络服务器,并且只打算托管一个通常生成 动态内容的“ Rack App”。Rack 应用程序也可以提供静态内容,但它的效率低于大多数其他传统的网络服务器。

大多数 RoR 设置使用传统 Web 服务器和 Rack 服务器的组合,以最大限度地发挥两者的功能。通过代理平衡和提供静态内容,Nginx 在请求重定向方面非常快。Unicorn 完全有能力处理 HTTP 报头和平衡 Ruby 的入站请求。

这个答案是对其他答案的补充,并解释了 为什么独角兽需要 nginx 在它前面

DR Unicorn 通常与 nginx 这样的反向代理一起部署的原因是,它的创建者故意将其设计成这样,为简单性做出了权衡。

首先,没有什么可以阻止您部署 Unicorn 没有反向代理。然而,这不是一个很好的主意; 让我们看看为什么。

Unicorn 遵循 Unix 的理念,即为 做好一件事服务,也就是为 快速,低延迟的客户端服务(稍后我们将看到这意味着什么)。事实上,独角兽是为 快速,低延迟的客户端设计的,这也意味着它不是很好与 缓慢,高延迟的客户,这确实是真的。这是独角兽的弱点之一,也是反向代理发挥作用的地方: 它坐在独角兽的前面,负责那些 慢客户(我们稍后会看到 怎么做)。

幸运的是,这样的反向代理已经存在,称为 Nginx

决定只处理快速客户端,极大地简化了 Unicorn 的设计,并允许更简单和更小的代码库,代价是增加了部署部门的复杂性(即。除了 Unicorn 之外,还必须部署 nginx)。

另一个选择可能是设计独角兽的方式不需要反向代理。然而,这意味着它必须实现额外的功能来完成现在 nginx 所做的所有事情,从而导致更复杂的代码库和更多的工程工作。

相反,它的创造者决定利用现有的经过实战测试和设计良好的软件,避免在其他软件已经解决的问题上浪费时间和精力。

让我们从技术角度来回答你的问题:

为什么 Unicorn 需要与 nginx 一起部署?

以下是一些关键原因:

Unicorn 对客户端使用阻塞 I/O

依赖反向代理意味着 Unicorn 不使用 需要来使用非阻塞 I/O,而是可以使用阻塞 I/O,这对程序员来说本质上更简单、更容易遵循。

正如 设计文件所述:

[使用阻塞 I/O ]允许在 Ruby 解释器中遵循更简单的代码路径,并且减少了系统调用。

然而,这也有一些后果:

关键点 # 1: 对于速度慢的客户端,Unicorn 效率不高

(为简单起见,我们假设设置为1个 Unicorn worker)

因为使用了阻塞 I/O,所以 一个独角兽工人一次只能服务一个客户是一个缓慢的客户端(即。一个连接缓慢的客户机)将有效地使工作者忙碌更长的时间(比快速客户机所做的)。与此同时,其他客户只是等待,直到工人重获自由(即。请求会堆积在队列中)。

为了解决这个问题,在 Unicorn 前面部署了一个反向代理,即 完全缓冲传入请求 还有应用程序响应,然后将它们分别发送给 Unicorn 和客户端。在这方面,您可以说反向代理“保护”Unicorn 不受慢速网络客户端的影响。

幸运的是,Nginx 是这个角色的一个很好的候选者,因为它被设计为高效地处理数以千计的并发客户机。

至关重要的是,反向代理应该在与 Unicorn 相同的本地网络中(通常在通过 Unix domain socket 连接 w/Unicorn 的同一物理机器中) ,以便将网络延迟保持在最低限度。

因此,这样一个代理有效地扮演了一个 快客户的角色,独角兽被设计成服务在第一位,因为它代理请求到独角兽 很快和保持工人忙碌的 在尽可能短的时间内(相比多少时间,一个客户端与一个缓慢的连接会做)。

关键点 # 2: Unicorn 不支持 HTTP/1.1 keep-alive

由于 Unicorn 使用了阻塞 I/O,这也意味着它不能支持 HTTP/1.1 keep-alive 特性,因为慢客户机的持久连接将很快占用所有可用的 Unicorn 工作人员。

因此,为了利用 HTTP keep-alive,需要使用反向代理。

另一方面,nginx 只需要几个线程就可以处理数千个并发连接。因此,它没有 Unicorn 这样的服务器所具有的并发性限制(这实际上限制了工作进程的数量) ,这意味着它可以很好地处理持久连接。在 给你中可以找到更多这方面的工作原理。

这就是为什么 nginx 接受来自客户端的 keep-alive 连接,并通过典型的 Unix 套接字通过普通连接代理它们到 Unicorn。

第三点: Unicorn 不太擅长提供静态文件

同样,提供静态文件是 Unicorn 可以所做的事情,但它的设计并不是为了提高效率。

另一方面,像 nginx 这样的反向代理在这方面做得更好(比如 sendfile(2)和缓存)。

更多

哲学文件中还列出了其他一些要点(见 “通过反向代理改进性能”)。

也可以参考一些 Nginx 的基本特性

我们看到,通过利用现有的软件(即。Nginx)和遵循 Unix 的哲学“做一件事,做好它”,Unicorn 能够遵循一个更简单的设计和实现,同时保持有效地服务 Rack 应用程序(例如你的 Rails 应用程序)。

更多信息请参考 Unicorn 的 哲学设计文档,它们更详细地解释了 Unicorn 设计背后的选择,以及为什么 nginx 被认为是 Unicorn 的一个很好的反向代理。